Related
I have a to do list that I need to sort by dueDate and by status (incomplete => complete). The incomplete tasks should be in ASC order by dueDate. Then the completed tasks should come after incomplete tasks and they should also be in ASC order by dueDate.
unsorted array
[{"task":"Dishes", "isComplete":false, "dueDate":"2021-01-01T15:45:00.000Z"},{"task":"feed baby", "isComplete":true, "dueDate":"2021-01-02T15:45:00.000Z"},{"task":"Laundry", "isComplete":true, "dueDate":"2021-01-04T15:45:00.000Z"},{"task":"Homework", "isComplete":false, "dueDate":"2021-01-03T15:45:00.000Z"}]
sorted array
[
{
"task":"Dishes",
"isComplete":false,
"dueDate":"2021-01-01T15:45:00.000Z"
},
{
"task":"Homework",
"isComplete":false,
"dueDate":"2021-01-03T15:45:00.000Z"
}
{
"task":"feed baby",
"isComplete":true,
"dueDate":"2021-01-02T15:45:00.000Z"
},
{
"task":"Laundry",
"isComplete":true,
"dueDate":"2021-01-04T15:45:00.000Z"
},
]
Here is my approach using 2 sort functions, first by date then by status but I feel it can be reduced further:
const sortByDate = (a,b) => {
if (new Date(a.dueDate) < new Date(b.dueDate)){
return -1;
}
if (new Date(a.dueDate) > new Date(b.dueDate)) {
return 1;
}
return 0;
}
const sortByStatus = (a,b) => {
if (a.isComplete < b.isComplete){
return -1;
}
if (a.isComplete > b.isComplete) {
return 1;
}
return 0;
}
You can use the coercive property of subtraction and the logical OR operator.
const arr = [{"task":"Dishes", "isComplete":false, "dueDate":"2021-01-01T15:45:00.000Z"},{"task":"feed baby", "isComplete":true, "dueDate":"2021-01-02T15:45:00.000Z"},{"task":"Laundry", "isComplete":true, "dueDate":"2021-01-04T15:45:00.000Z"},{"task":"Homework", "isComplete":false, "dueDate":"2021-01-03T15:45:00.000Z"}];
arr.sort((a,b) => a.isComplete - b.isComplete || new Date(a.dueDate) - new Date(b.dueDate));
console.log(arr);
If you are asking for a combined sort function. Then this should do the work
const sortArray = (a,b) => {
if (new Date(a.dueDate) < new Date(b.dueDate)){
return -1;
}
else if (new Date(a.dueDate) > new Date(b.dueDate)) {
return 1;
}
else { // This else means, due date is same, and we need to consider the status in this case
if (b.isComplete){
return 1;
}
else if (a.isComplete) {
return -1;
}
return 0; // This means status and due date are equal
}
};
First this will sort by the due date. If the due dates are equal, then the status will be considered for such elements.
array.sort((a, b) => {
return sortByStatus(a,b) || sortByDate(a, b);
});
More descriptive
array.sort((a, b) => {
const byStatus = sortByStatus(a, b)
// if status isn't same, compare by status
if( byStatus !== 0 ) return byStatus;
// else compare by date
return sortByDate(a,b);
});
try this.
unsorted_arr =
[{"task":"Dishes", "isComplete":false, "dueDate":"2021-01-01T15:45:00.000Z"},{"task":"feed baby", "isComplete":true, "dueDate":"2021-01-02T15:45:00.000Z"},{"task":"Laundry", "isComplete":true, "dueDate":"2021-01-04T15:45:00.000Z"},{"task":"Homework", "isComplete":false, "dueDate":"2021-01-03T15:45:00.000Z"}];
unsorted_arr.sort(function (a, b) {
if(a.isComplete == b.isComplete)
return (a.dueDate < b.dueDate) ? -1 : (a.dueDate > b.dueDate) ? 1 : 0;
else
return (a.isComplete < b.isComplete) ? -1 : 1;
});
console.log(unsorted_arr);
Try this one:
var array = [{"task":"Dishes", "isComplete":false, "dueDate":"2021-01-01T15:45:00.000Z"},{"task":"feed baby", "isComplete":true, "dueDate":"2021-01-02T15:45:00.000Z"},{"task":"Laundry", "isComplete":true, "dueDate":"2021-01-04T15:45:00.000Z"},{"task":"Homework", "isComplete":false, "dueDate":"2021-01-03T15:45:00.000Z"}]
var newarray = array.sort((a, b) => {
const date = new Date(a.dueDate) - new Date(b.dueDate);
const isComplete = a.isComplete - b.isComplete;
return isComplete || date ;
})
console.log(newarray);
I have a JavaScript array of dates (as strings) like the following:
["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"]
I want to convert this into an array of arrays of [first, last] contiguous date ranges, e.g., as below:
[["2020-07-24T04:00:00.000Z", "2020-08-01T04:00:00.000Z"], ["2020-11-29T05:00:00.000Z"], ["2020-12-30T05:00:00.000Z", "2021-01-02T05:00:00.000Z"], []]
How do I do this? Code attempt below:
var ranges = [];
for (var i = 0; i < popNull.length; i++) {
let currentRange = [];
let current = new Date(popNull[i]);
let tomorrow = new Date(current.getTime() + (24 * 60 * 60 * 1000));
let next = new Date(popNull[i+1]);
if (next === tomorrow) {
}
else {
}
}
I've made a couple of assumptions in the code below
That the dates are pre-sorted in ascending date order
That "contiguous" means less than or equal to 24 hours.
All dates are formatted in a way that can be passed directly to the Date constructor on the platform of choice.
const input = ["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"].map(x => new Date(x));
let aggregation = input.reduce( (acc,i) => {
if(acc.prev){
const diffInHrs = (i - acc.prev)/1000/60/60;
if(diffInHrs <= 24){
acc.result[acc.result.length-1][1] = i;
}
else{
acc.result.push([i])
}
acc.prev = i;
return acc;
}
else{
return {prev:i, result:[[i]]}
}
},{});
console.log(aggregation.result)
You can reduce the dates by keeoing track of the latest and checking the current with the previous. You can diff their epoch valyes and check if they are within a day.
const dates = ["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"];
const DAY_MILLIS = 8.64e7;
const ranges = dates
.reduce((acc, dateStr, index, all) => {
const dateObj = new Date(dateStr);
if (acc.length === 0) {
acc.push({ start: dateObj, prev: dateObj });
} else {
let last = acc[acc.length - 1];
const { start, prev } = last;
if (dateObj.getTime() - prev.getTime() <= DAY_MILLIS) {
last.prev = dateObj;
} else {
last.end = prev;
acc.push({ start: dateObj, prev: dateObj });
}
if (index === all.length - 1) {
last = acc[acc.length - 1];
if (last.end == null) {
last.end = last.prev;
}
}
}
return acc;
}, [])
.map(({ start, prev, end }) =>
((startStr, endStr) =>
startStr !== endStr ? [startStr, endStr] : [startStr])
(start.toISOString(), end.toISOString()));
console.log(ranges);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Output
[
[ "2020-07-24T04:00:00.000Z", "2020-08-01T04:00:00.000Z" ],
[ "2020-11-29T05:00:00.000Z" ],
[ "2020-12-30T05:00:00.000Z", "2021-01-02T05:00:00.000Z" ],
[ "2021-02-18T05:00:00.000Z" ]
]
You can do the following using Array#reduce():
Go through each date.
Check if the current date will extend last range.
if yes, then overwrite the end in the range pair (second element)
if no, start a new range
If it happens that a range only has a single date, then use the start to compare with. The logic still holds - extending the range will add a second date. If the new date is not within the desired time frame, then a new range is created and the previous range is left with a single element in it.
const areDatesWithin = ms => (str1, str2) => {
if (!str1 || !str2)
return false;
const date1 = new Date(str1);
const date2 = new Date(str2);
return (date2 - date1) <= ms;
}
const areDatesWithin1Day = areDatesWithin(1000 * 60 * 60 * 24);
function combineInRanges(dates) {
return dates.reduce((acc, nextDate) => {
const lastDateRange = acc[acc.length-1] ?? [];
//compare with range end (if there) or range start
const lastDate = lastDateRange[1] ?? lastDateRange[0];
//check if the range needs to be extended
const mergeWithRange = areDatesWithin1Day(lastDate, nextDate);
if (mergeWithRange) {
//change the end of the range
lastDateRange[1] = nextDate;
} else {
//start a new range
acc.push([nextDate]);
}
return acc;
}, []);
}
const arr = ["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"];
console.log(combineInRanges(arr));
https://stackoverflow.com/a/67182108/20667780
Jamiec answer is working. If you have a date array with UTC dates correctly offsetted to local timezone, then the daylight save start/end date will have more than 24 hours. You have to change the diffInHrs to 25 instead of 24.
Otherwise, its a perfect answer.
It's a sort of reduction based on the even-ness of the index...
let array = ['a', 'b', 'c', 'd', 'e', 'f'];
let pairs = array.reduce((acc, el, idx) => {
idx % 2 ? acc[acc.length-1].push(el) : acc.push([el]);
return acc;
}, []);
console.log(pairs)
Say I have an array of a few objects:
var array = [{id: 1, date: Mar 12 2012 10:00:00 AM}, {id: 2, date: Mar 8 2012 08:00:00 AM}];
How can I sort this array by the date element in order from the date closest to the current date and time down? Keep in mind that the array may have many objects, but for the sake of simplicity I used 2.
Would I use the sort function and a custom comparator?
Simplest Answer
array.sort(function(a,b){
// Turn your strings into dates, and then subtract them
// to get a value that is either negative, positive, or zero.
return new Date(b.date) - new Date(a.date);
});
More Generic Answer
array.sort(function(o1,o2){
if (sort_o1_before_o2) return -1;
else if(sort_o1_after_o2) return 1;
else return 0;
});
Or more tersely:
array.sort(function(o1,o2){
return sort_o1_before_o2 ? -1 : sort_o1_after_o2 ? 1 : 0;
});
Generic, Powerful Answer
Define a custom non-enumerable sortBy function using a Schwartzian transform on all arrays :
(function(){
if (typeof Object.defineProperty === 'function'){
try{Object.defineProperty(Array.prototype,'sortBy',{value:sb}); }catch(e){}
}
if (!Array.prototype.sortBy) Array.prototype.sortBy = sb;
function sb(f){
for (var i=this.length;i;){
var o = this[--i];
this[i] = [].concat(f.call(o,o,i),o);
}
this.sort(function(a,b){
for (var i=0,len=a.length;i<len;++i){
if (a[i]!=b[i]) return a[i]<b[i]?-1:1;
}
return 0;
});
for (var i=this.length;i;){
this[--i]=this[i][this[i].length-1];
}
return this;
}
})();
Use it like so:
array.sortBy(function(o){ return o.date });
If your date is not directly comparable, make a comparable date out of it, e.g.
array.sortBy(function(o){ return new Date( o.date ) });
You can also use this to sort by multiple criteria if you return an array of values:
// Sort by date, then score (reversed), then name
array.sortBy(function(o){ return [ o.date, -o.score, o.name ] };
See http://phrogz.net/JS/Array.prototype.sortBy.js for more details.
#Phrogz answers are both great, but here is a great, more concise answer:
array.sort(function(a,b){return a.getTime() - b.getTime()});
Using the arrow function way
array.sort((a,b)=>a.getTime()-b.getTime());
found here: Sort date in Javascript
After correcting the JSON this should work for you now:
var array = [{id: 1, date:'Mar 12 2012 10:00:00 AM'}, {id: 2, date:'Mar 8 2012 08:00:00 AM'}];
array.sort(function(a, b) {
var c = new Date(a.date);
var d = new Date(b.date);
return c-d;
});
Your data needs some corrections:
var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];
After correcting the data, you can use this piece of code:
function sortFunction(a,b){
var dateA = new Date(a.date).getTime();
var dateB = new Date(b.date).getTime();
return dateA > dateB ? 1 : -1;
};
var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];
array.sort(sortFunction);β
Above answers are all good π, here is my implementation of sorting date in ES6 way, I'm using Date.parse (is global Date object) this will convert string representation of Date to number of milliseconds. Instead of instantiating new Date object every time.
var array = ["2021-08-10T07:24:30.087+0000" , "2021-09-30T07:24:30.087+0000", "2021-10-13T07:24:30.087+0000"];
// sorting with latest date
array.sort((a,b) => Date.parse(b) - Date.parse(a))
I recommend GitHub: Array sortBy - a best implementation of sortBy method which uses the Schwartzian transform
But for now we are going to try this approach Gist: sortBy-old.js.
Let's create a method to sort arrays being able to arrange objects by some property.
Creating the sorting function
var sortBy = (function () {
var toString = Object.prototype.toString,
// default parser function
parse = function (x) { return x; },
// gets the item to be sorted
getItem = function (x) {
var isObject = x != null && typeof x === "object";
var isProp = isObject && this.prop in x;
return this.parser(isProp ? x[this.prop] : x);
};
/**
* Sorts an array of elements.
*
* #param {Array} array: the collection to sort
* #param {Object} cfg: the configuration options
* #property {String} cfg.prop: property name (if it is an Array of objects)
* #property {Boolean} cfg.desc: determines whether the sort is descending
* #property {Function} cfg.parser: function to parse the items to expected type
* #return {Array}
*/
return function sortby (array, cfg) {
if (!(array instanceof Array && array.length)) return [];
if (toString.call(cfg) !== "[object Object]") cfg = {};
if (typeof cfg.parser !== "function") cfg.parser = parse;
cfg.desc = !!cfg.desc ? -1 : 1;
return array.sort(function (a, b) {
a = getItem.call(cfg, a);
b = getItem.call(cfg, b);
return cfg.desc * (a < b ? -1 : +(a > b));
});
};
}());
Setting unsorted data
var data = [
{date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: 0, type: "cash"},
{date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
{date: "2011-11-14T16:30:43Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T17:22:59Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:53:41Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:48:46Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"},
{date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
{date: "2011-11-14T16:58:03Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"},
{date: "2011-11-14T17:07:21Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0, type: "cash"}
];
Using it
Finally, we arrange the array, by "date" property as string
//sort the object by a property (ascending)
//sorting takes into account uppercase and lowercase
sortBy(data, { prop: "date" });
If you want to ignore letter case, set the "parser" callback:
//sort the object by a property (descending)
//sorting ignores uppercase and lowercase
sortBy(data, {
prop: "date",
desc: true,
parser: function (item) {
//ignore case sensitive
return item.toUpperCase();
}
});
If you want to treat the "date" field as Date type:
//sort the object by a property (ascending)
//sorting parses each item to Date type
sortBy(data, {
prop: "date",
parser: function (item) {
return new Date(item);
}
});
Here you can play with the above example:
jsbin.com/lesebi
This should do when your date is in this format (dd/mm/yyyy).
sortByDate(arr) {
arr.sort(function(a,b){
return Number(new Date(a.readableDate)) - Number(new Date(b.readableDate));
});
return arr;
}
Then call sortByDate(myArr);
arr is an array of object and each object has date_prop which is a date. You can sort it in descending/decreasing order like this
arr = arr.sort(function (a, b) {
var dateA = new Date(a.date_prop).getTime();
var dateB = new Date(b.date_prop).getTime();
return dateA < dateB ? 1 : -1; // ? -1 : 1 for ascending/increasing order
});
You could use sortBy in underscore js.
http://underscorejs.org/#sortBy
Sample:
var log = [{date: '2016-01-16T05:23:38+00:00', other: 'sample'},
{date: '2016-01-13T05:23:38+00:00',other: 'sample'},
{date: '2016-01-15T11:23:38+00:00', other: 'sample'}];
console.log(_.sortBy(log, 'date'));
With ES6 arrow functions, you can further write just one line of concise code (excluding variable declaration).
Eg.:
var isDescending = true; //set to false for ascending
console.log(["8/2/2020","8/1/2020","8/13/2020", "8/2/2020"].sort((a,b) => isDescending ? new Date(b).getTime() - new Date(a).getTime() : new Date(a).getTime() - new Date(b).getTime()));
Since time does not exists with the above dates, the Date object will consider following default time for sorting:
00:00:00
The code will work for both ascending and descending sort.
Just change the value of isDescending variable as required.
Strings with dates are comparable in JavaScript (if they are syntactically the same), e.g.:
'2020-12-01' < '2020-12-02' == true
This means you can use this expression in a custom sort function:
var arr = [{id:1, date:'2020-12-01'}, {id:1, date:'2020-12-15'}, {id:1, date:'2020-12-12'}]
function sortByDate(a, b) {
if (a.date < b.date) {
return 1;
}
if (a.date > b.date) {
return -1;
}
return 0;
}
const sorted = arr.sort(sortByDate);
console.log(sorted);
I'm going to add this here, as some uses may not be able to work out how to invert this sorting method.
To sort by 'coming up', we can simply swap a & b, like so:
your_array.sort ( (a, b) => {
return new Date(a.DateTime) - new Date(b.DateTime);
});
Notice that a is now on the left hand side, and b is on the right, :D!
i was able to achieve sorting using below lines:
array.sort(function(a, b)
{
if (a.DueDate > b.DueDate) return 1;
if (a.DueDate < b.DueDate) return -1;
})
I personally use following approach to sort dates.
let array = ["July 11, 1960", "February 1, 1974", "July 11, 1615", "October 18, 1851", "November 12, 1995"];
array.sort(function(date1, date2) {
date1 = new Date(date1);
date2 = new Date(date2);
if (date1 > date2) return 1;
if (date1 < date2) return -1;
})
Adding absolute will give better results
var datesArray =[
{"some":"data1","date": "2018-06-30T13:40:31.493Z"},
{"some":"data2","date": "2018-07-04T13:40:31.493Z"},
{"some":"data3","date": "2018-06-27T13:40:54.394Z"}
]
var sortedJsObjects = datesArray.sort(function(a,b){
return Math.abs(new Date(a.date) - new Date(b.date))
});
Here is the shortest way to solve your problem.
var array = [{id: 1, date: 'Mar 12 2012 10:00:00 AM'}, {id: 2, date: 'Mar 8 2012 08:00:00 AM'}];
var sortedArray = array.sort((a,b) => Date.parse(new Date(a.date)) - Date.parse(new Date(b.date)));
Thank you Ganesh Sanap. sorting items by date field from old to new. Use it
myArray = [{transport: "Air",
load: "Vatican Vaticano",
created: "01/31/2020"},
{transport: "Air",
load: "Paris",
created: "01/30/2020"}]
myAarray.sort(function(a, b) {
var c = new Date(a.created);
var d = new Date(b.created);
return c-d;
});
Simple one line solution for me to sort dates :
sort((a, b) => (a < b ? 1 : -1))
["12 Jan 2018" , "1 Dec 2018", "04 May 2018"].sort(function(a,b) {
return new Date(a).getTime() - new Date(b).getTime()
})
For anyone who is wanting to sort by date (UK format), I used the following:
//Sort by day, then month, then year
for(i=0;i<=2; i++){
dataCourses.sort(function(a, b){
a = a.lastAccessed.split("/");
b = b.lastAccessed.split("/");
return a[i]>b[i] ? -1 : a[i]<b[i] ? 1 : 0;
});
}
I have just taken the Schwartzian transform depicted above and made as function. It takes an array, the sorting function and a boolean as input:
function schwartzianSort(array,f,asc){
for (var i=array.length;i;){
var o = array[--i];
array[i] = [].concat(f.call(o,o,i),o);
}
array.sort(function(a,b){
for (var i=0,len=a.length;i<len;++i){
if (a[i]!=b[i]) return a[i]<b[i]?asc?-1:1:1;
}
return 0;
});
for (var i=array.length;i;){
array[--i]=array[i][array[i].length-1];
}
return array;
}
function schwartzianSort(array, f, asc) {
for (var i = array.length; i;) {
var o = array[--i];
array[i] = [].concat(f.call(o, o, i), o);
}
array.sort(function(a, b) {
for (var i = 0, len = a.length; i < len; ++i) {
if (a[i] != b[i]) return a[i] < b[i] ? asc ? -1 : 1 : 1;
}
return 0;
});
for (var i = array.length; i;) {
array[--i] = array[i][array[i].length - 1];
}
return array;
}
arr = []
arr.push({
date: new Date(1494434112806)
})
arr.push({
date: new Date(1494434118181)
})
arr.push({
date: new Date(1494434127341)
})
console.log(JSON.stringify(arr));
arr = schwartzianSort(arr, function(o) {
return o.date
}, false)
console.log("DESC", JSON.stringify(arr));
arr = schwartzianSort(arr, function(o) {
return o.date
}, true)
console.log("ASC", JSON.stringify(arr));
If like me you have an array with dates formatted like YYYY[-MM[-DD]] where you'd like to order more specific dates before less specific ones, I came up with this handy function:
function sortByDateSpecificity(a, b) {
const aLength = a.date.length
const bLength = b.date.length
const aDate = a.date + (aLength < 10 ? '-12-31'.slice(-10 + aLength) : '')
const bDate = b.date + (bLength < 10 ? '-12-31'.slice(-10 + bLength) : '')
return new Date(aDate) - new Date(bDate)
}
Thanks for those brilliant answers on top. I have thought a slightly complicated answer. Just for those who want to compare different answers.
const data = [
'2-2018', '1-2018',
'3-2018', '4-2018',
'1-2019', '2-2019',
'3-2019', '4-2019',
'1-2020', '3-2020',
'4-2020', '1-2021'
]
let eachYearUniqueMonth = data.reduce((acc, elem) => {
const uniqueDate = Number(elem.match(/(\d+)\-(\d+)/)[1])
const uniqueYear = Number(elem.match(/(\d+)\-(\d+)/)[2])
if (acc[uniqueYear] === undefined) {
acc[uniqueYear] = []
} else{
if (acc[uniqueYear] && !acc[uniqueYear].includes(uniqueDate)) {
acc[uniqueYear].push(uniqueDate)
}
}
return acc;
}, {})
let group = Object.keys(eachYearUniqueMonth).reduce((acc,uniqueYear)=>{
eachYearUniqueMonth[uniqueYear].forEach(uniqueMonth=>{
acc.push(`${uniqueYear}-${uniqueMonth}`)
})
return acc;
},[])
console.log(group); //["2018-1", "2018-3", "2018-4", "2019-2", "2019-3", "2019-4", "2020-3", "2020-4"]
I have an array of objects in which key 'time' contains the date in ISO format
Example - 2021-12-24T11:02:20.370705
arr.sort(function(a,b){return a.time > b.time ? 1 : a.time < b.time ? -1 : 0 });
Above worked for me like a charm!
If you are into MongoDB, one of the solutions is:
db.collection.find({}).sort("your date field");
For example:
db.collection.find({}).sort("createdAt");
Well, I have an array objects with random values,
Ex.
var arr = [
{ id:1001, date:"20-02-2014", Name: 'demo1' },
{ id:1004, date:"13-02-2014", Name: 'demo0' },
{ id:1000, date:"10-02-2014", Name: 'demo14' },
{ id:1004, date:"16-02-2014", Name: 'demo10' },
{ id:1006, date:"22-02-2014", Name: 'demo111' },
{ id:1003, date:"28-02-2014", Name: 'demo16' },
{ id:1000, date:"28-01-2014", Name: 'demo12' },
{ id:1004, date:"28-01-2014", Name: 'demo01' },
{ id:1000, date:"08-01-2014", Name: 'demo41' },
{ id:1006, date:"08-01-2014", Name: 'demo91' }
]
I wanted to sort this array firstly by key id & then by key date as,
Output:
sorted_arr = [
{"id":1000,"date":"08-01-2014","Name":"demo41"}, //group1
{"id":1000,"date":"28-01-2014","Name":"demo12"}, //group1
{"id":1000,"date":"10-02-2014","Name":"demo14"}, //group1
{"id":1001,"date":"20-02-2014","Name":"demo1"}, //group2
{"id":1003,"date":"28-02-2014","Name":"demo16"}, //group3
{"id":1004,"date":"28-01-2014","Name":"demo01"}, //group4
{"id":1004,"date":"13-02-2014","Name":"demo0"}, //group4
{"id":1004,"date":"16-02-2014","Name":"demo10"}, //group4
{"id":1006,"date":"08-01-2014","Name":"demo91"} //group5
{"id":1006,"date":"22-02-2014","Name":"demo111"} //group5
]
I tried few generic code to sort,
// generic comparison function
cmp = function(x, y){
return x > y ? 1 : x < y ? -1 : 0;
};
arr.sort(function(a, b){
return cmp(
[cmp(a.id, b.id), cmp(a.date, b.date)],
[cmp(b.id, a.id), cmp(b.date, a.date)]
);
});
I referred few examples SO Example but not getting expected output. Please suggest me best way to get this.
No need to create Date objects, just reorder the date string into a sortable string, example
This example assumes that your dates are in the same format DD-MM-YYYY and creates YYYYMMDD for the date sort.
Javascript
var arr = [
{ id:1001, date:"20-02-2014", Name: 'demo1' },
{ id:1004, date:"13-02-2014", Name: 'demo0' },
{ id:1000, date:"10-02-2014", Name: 'demo14' },
{ id:1004, date:"16-02-2014", Name: 'demo10' },
{ id:1006, date:"22-02-2014", Name: 'demo111' },
{ id:1003, date:"28-02-2014", Name: 'demo16' },
{ id:1000, date:"28-01-2014", Name: 'demo12' },
{ id:1004, date:"28-01-2014", Name: 'demo01' },
{ id:1000, date:"08-01-2014", Name: 'demo41' },
{ id:1006, date:"08-01-2014", Name: 'demo91' }
];
var sorted = arr.sort(function (a, b) {
return a.id - b.id || a.date.split('-').reverse().join('') - b.date.split('-').reverse().join('');
});
sorted.forEach(function (element) {
console.log(JSON.stringify(element));
});
Output
{"id":1000,"date":"08-01-2014","Name":"demo41"}
{"id":1000,"date":"28-01-2014","Name":"demo12"}
{"id":1000,"date":"10-02-2014","Name":"demo14"}
{"id":1001,"date":"20-02-2014","Name":"demo1"}
{"id":1003,"date":"28-02-2014","Name":"demo16"}
{"id":1004,"date":"28-01-2014","Name":"demo01"}
{"id":1004,"date":"13-02-2014","Name":"demo0"}
{"id":1004,"date":"16-02-2014","Name":"demo10"}
{"id":1006,"date":"08-01-2014","Name":"demo91"}
{"id":1006,"date":"22-02-2014","Name":"demo111"}
On jsFiddle
If there is any concern over mixing date formats, as discussed with #xdazz, then you can improve on this by checking the padding yourself. The following creates the format 'YYYYYYMMDD' when sorting by the date. The extra year padding is not necessary in this example as I am taking the numeric difference of the values, but if you choose to compare the strings then it is important.
function pad(s, n) {
var v = '',
i;
for(i = 0; i < n - s.length; i += 1) {
v += '0';
}
return v + s;
}
var sorted = arr.sort(function (a, b) {
var idDiff = a.id - b.id;
if (idDiff) {
return idDiff;
}
var ordA = a.date.split('-').reverse(),
ordB = b.date.split('-').reverse();
ordA[0] = pad(ordA[0], 6);
ordA[1] = pad(ordA[1], 2);
ordA[2] = pad(ordA[2], 2);
ordA = ordA.join('');
ordB[0] = pad(ordB[0], 6);
ordB[1] = pad(ordB[1], 2);
ordB[2] = pad(ordB[2], 2);
ordB = ordB.join('');
return ordA - ordB;
});
On jsFiddle
If you really want to use Date objects the I would suggest the following.
var sorted = arr.sort(function (a, b) {
var idDiff = a.id - b.id;
if (idDiff) {
return idDiff;
}
var ordA = a.date.split('-').reverse(),
ordB = b.date.split('-').reverse();
ordA[1] -= 1;
ordB[1] -= 1;
return new Date(Date.UTC.apply(undefined, ordA)).valueOf() - new Date(Date.UTC.apply(undefined, ordB)).valueOf();
});
sorted.forEach(function (element) {
console.log(JSON.stringify(element));
});
On jsFiddle
Note: These examples do not handle dates with negative years, again you would need to make further modifications.
First compare with id, then compare with date if id equal. But because your date is in invalid date format, extra work has to be done for letting it be recognized by Date.
sorted_arr = arr.sort(function(a, b) {
return a.id - b.id || new Date(a.date.split('-').reverse().join('-')) - new Date(b.date.split('-').reverse().join('-'));
});
Edit:
If you are guaranteed to have zeros in front of the 1-digit months and dates, then you could even not to parse to date:
sorted_arr = arr.sort(function(a, b) {
return a.id - b.id || a.date.split('-').reverse().join('') - b.date.split('-').reverse().join('');
});
It's better to have a date operate lib momentjs to help.
You could check the code on jsBin
function compare(a, b){
var idDiff = a.id - b.id;
var adate = moment(a.date, "DD-MM-YYYY");
var bdate = moment(b.date, "DD-MM-YYYY");
var dateDiff = adate.diff(bdate);
return idDiff || dateDiff;
}
var sortedArr = arr.sort(compare);
console.log(sortedArr);
You can sort array by two properties with Alasql library:
var res = alasql('SELECT *, mid(date,7,4)+mid(date,4,2)+mid(date,1,2) AS ndate \
FROM ? ORDER BY id, ndate',[arr]);
Try this example at jsFiddle.
Here "mid(date,7,4)+mid(date,4,2)+mid(date,1,2)" was used to convert date from '28-11-2014' to the sort key like '20141128'.
Came up with this using underscore.js & it's chain and sortBy:
var sorted_array = _(arr).chain().sortBy(function(o) {
return o.date.split('-').reverse().join();
}).sortBy(function(o) {
return o.id;
}).value();
Sorting on the date first, and then id will give you the list sorted as expected.
jsfiddle
Say I have an array of a few objects:
var array = [{id: 1, date: Mar 12 2012 10:00:00 AM}, {id: 2, date: Mar 8 2012 08:00:00 AM}];
How can I sort this array by the date element in order from the date closest to the current date and time down? Keep in mind that the array may have many objects, but for the sake of simplicity I used 2.
Would I use the sort function and a custom comparator?
Simplest Answer
array.sort(function(a,b){
// Turn your strings into dates, and then subtract them
// to get a value that is either negative, positive, or zero.
return new Date(b.date) - new Date(a.date);
});
More Generic Answer
array.sort(function(o1,o2){
if (sort_o1_before_o2) return -1;
else if(sort_o1_after_o2) return 1;
else return 0;
});
Or more tersely:
array.sort(function(o1,o2){
return sort_o1_before_o2 ? -1 : sort_o1_after_o2 ? 1 : 0;
});
Generic, Powerful Answer
Define a custom non-enumerable sortBy function using a Schwartzian transform on all arrays :
(function(){
if (typeof Object.defineProperty === 'function'){
try{Object.defineProperty(Array.prototype,'sortBy',{value:sb}); }catch(e){}
}
if (!Array.prototype.sortBy) Array.prototype.sortBy = sb;
function sb(f){
for (var i=this.length;i;){
var o = this[--i];
this[i] = [].concat(f.call(o,o,i),o);
}
this.sort(function(a,b){
for (var i=0,len=a.length;i<len;++i){
if (a[i]!=b[i]) return a[i]<b[i]?-1:1;
}
return 0;
});
for (var i=this.length;i;){
this[--i]=this[i][this[i].length-1];
}
return this;
}
})();
Use it like so:
array.sortBy(function(o){ return o.date });
If your date is not directly comparable, make a comparable date out of it, e.g.
array.sortBy(function(o){ return new Date( o.date ) });
You can also use this to sort by multiple criteria if you return an array of values:
// Sort by date, then score (reversed), then name
array.sortBy(function(o){ return [ o.date, -o.score, o.name ] };
See http://phrogz.net/JS/Array.prototype.sortBy.js for more details.
#Phrogz answers are both great, but here is a great, more concise answer:
array.sort(function(a,b){return a.getTime() - b.getTime()});
Using the arrow function way
array.sort((a,b)=>a.getTime()-b.getTime());
found here: Sort date in Javascript
After correcting the JSON this should work for you now:
var array = [{id: 1, date:'Mar 12 2012 10:00:00 AM'}, {id: 2, date:'Mar 8 2012 08:00:00 AM'}];
array.sort(function(a, b) {
var c = new Date(a.date);
var d = new Date(b.date);
return c-d;
});
Your data needs some corrections:
var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];
After correcting the data, you can use this piece of code:
function sortFunction(a,b){
var dateA = new Date(a.date).getTime();
var dateB = new Date(b.date).getTime();
return dateA > dateB ? 1 : -1;
};
var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];
array.sort(sortFunction);β
Above answers are all good π, here is my implementation of sorting date in ES6 way, I'm using Date.parse (is global Date object) this will convert string representation of Date to number of milliseconds. Instead of instantiating new Date object every time.
var array = ["2021-08-10T07:24:30.087+0000" , "2021-09-30T07:24:30.087+0000", "2021-10-13T07:24:30.087+0000"];
// sorting with latest date
array.sort((a,b) => Date.parse(b) - Date.parse(a))
I recommend GitHub: Array sortBy - a best implementation of sortBy method which uses the Schwartzian transform
But for now we are going to try this approach Gist: sortBy-old.js.
Let's create a method to sort arrays being able to arrange objects by some property.
Creating the sorting function
var sortBy = (function () {
var toString = Object.prototype.toString,
// default parser function
parse = function (x) { return x; },
// gets the item to be sorted
getItem = function (x) {
var isObject = x != null && typeof x === "object";
var isProp = isObject && this.prop in x;
return this.parser(isProp ? x[this.prop] : x);
};
/**
* Sorts an array of elements.
*
* #param {Array} array: the collection to sort
* #param {Object} cfg: the configuration options
* #property {String} cfg.prop: property name (if it is an Array of objects)
* #property {Boolean} cfg.desc: determines whether the sort is descending
* #property {Function} cfg.parser: function to parse the items to expected type
* #return {Array}
*/
return function sortby (array, cfg) {
if (!(array instanceof Array && array.length)) return [];
if (toString.call(cfg) !== "[object Object]") cfg = {};
if (typeof cfg.parser !== "function") cfg.parser = parse;
cfg.desc = !!cfg.desc ? -1 : 1;
return array.sort(function (a, b) {
a = getItem.call(cfg, a);
b = getItem.call(cfg, b);
return cfg.desc * (a < b ? -1 : +(a > b));
});
};
}());
Setting unsorted data
var data = [
{date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: 0, type: "cash"},
{date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
{date: "2011-11-14T16:30:43Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T17:22:59Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:53:41Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:48:46Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"},
{date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
{date: "2011-11-14T16:58:03Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"},
{date: "2011-11-14T17:07:21Z", quantity: 2, total: 90, tip: 0, type: "tab"},
{date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0, type: "cash"}
];
Using it
Finally, we arrange the array, by "date" property as string
//sort the object by a property (ascending)
//sorting takes into account uppercase and lowercase
sortBy(data, { prop: "date" });
If you want to ignore letter case, set the "parser" callback:
//sort the object by a property (descending)
//sorting ignores uppercase and lowercase
sortBy(data, {
prop: "date",
desc: true,
parser: function (item) {
//ignore case sensitive
return item.toUpperCase();
}
});
If you want to treat the "date" field as Date type:
//sort the object by a property (ascending)
//sorting parses each item to Date type
sortBy(data, {
prop: "date",
parser: function (item) {
return new Date(item);
}
});
Here you can play with the above example:
jsbin.com/lesebi
This should do when your date is in this format (dd/mm/yyyy).
sortByDate(arr) {
arr.sort(function(a,b){
return Number(new Date(a.readableDate)) - Number(new Date(b.readableDate));
});
return arr;
}
Then call sortByDate(myArr);
arr is an array of object and each object has date_prop which is a date. You can sort it in descending/decreasing order like this
arr = arr.sort(function (a, b) {
var dateA = new Date(a.date_prop).getTime();
var dateB = new Date(b.date_prop).getTime();
return dateA < dateB ? 1 : -1; // ? -1 : 1 for ascending/increasing order
});
You could use sortBy in underscore js.
http://underscorejs.org/#sortBy
Sample:
var log = [{date: '2016-01-16T05:23:38+00:00', other: 'sample'},
{date: '2016-01-13T05:23:38+00:00',other: 'sample'},
{date: '2016-01-15T11:23:38+00:00', other: 'sample'}];
console.log(_.sortBy(log, 'date'));
With ES6 arrow functions, you can further write just one line of concise code (excluding variable declaration).
Eg.:
var isDescending = true; //set to false for ascending
console.log(["8/2/2020","8/1/2020","8/13/2020", "8/2/2020"].sort((a,b) => isDescending ? new Date(b).getTime() - new Date(a).getTime() : new Date(a).getTime() - new Date(b).getTime()));
Since time does not exists with the above dates, the Date object will consider following default time for sorting:
00:00:00
The code will work for both ascending and descending sort.
Just change the value of isDescending variable as required.
Strings with dates are comparable in JavaScript (if they are syntactically the same), e.g.:
'2020-12-01' < '2020-12-02' == true
This means you can use this expression in a custom sort function:
var arr = [{id:1, date:'2020-12-01'}, {id:1, date:'2020-12-15'}, {id:1, date:'2020-12-12'}]
function sortByDate(a, b) {
if (a.date < b.date) {
return 1;
}
if (a.date > b.date) {
return -1;
}
return 0;
}
const sorted = arr.sort(sortByDate);
console.log(sorted);
I'm going to add this here, as some uses may not be able to work out how to invert this sorting method.
To sort by 'coming up', we can simply swap a & b, like so:
your_array.sort ( (a, b) => {
return new Date(a.DateTime) - new Date(b.DateTime);
});
Notice that a is now on the left hand side, and b is on the right, :D!
i was able to achieve sorting using below lines:
array.sort(function(a, b)
{
if (a.DueDate > b.DueDate) return 1;
if (a.DueDate < b.DueDate) return -1;
})
I personally use following approach to sort dates.
let array = ["July 11, 1960", "February 1, 1974", "July 11, 1615", "October 18, 1851", "November 12, 1995"];
array.sort(function(date1, date2) {
date1 = new Date(date1);
date2 = new Date(date2);
if (date1 > date2) return 1;
if (date1 < date2) return -1;
})
Adding absolute will give better results
var datesArray =[
{"some":"data1","date": "2018-06-30T13:40:31.493Z"},
{"some":"data2","date": "2018-07-04T13:40:31.493Z"},
{"some":"data3","date": "2018-06-27T13:40:54.394Z"}
]
var sortedJsObjects = datesArray.sort(function(a,b){
return Math.abs(new Date(a.date) - new Date(b.date))
});
Here is the shortest way to solve your problem.
var array = [{id: 1, date: 'Mar 12 2012 10:00:00 AM'}, {id: 2, date: 'Mar 8 2012 08:00:00 AM'}];
var sortedArray = array.sort((a,b) => Date.parse(new Date(a.date)) - Date.parse(new Date(b.date)));
Simple one line solution for me to sort dates :
sort((a, b) => (a < b ? 1 : -1))
Thank you Ganesh Sanap. sorting items by date field from old to new. Use it
myArray = [{transport: "Air",
load: "Vatican Vaticano",
created: "01/31/2020"},
{transport: "Air",
load: "Paris",
created: "01/30/2020"}]
myAarray.sort(function(a, b) {
var c = new Date(a.created);
var d = new Date(b.created);
return c-d;
});
["12 Jan 2018" , "1 Dec 2018", "04 May 2018"].sort(function(a,b) {
return new Date(a).getTime() - new Date(b).getTime()
})
For anyone who is wanting to sort by date (UK format), I used the following:
//Sort by day, then month, then year
for(i=0;i<=2; i++){
dataCourses.sort(function(a, b){
a = a.lastAccessed.split("/");
b = b.lastAccessed.split("/");
return a[i]>b[i] ? -1 : a[i]<b[i] ? 1 : 0;
});
}
I have just taken the Schwartzian transform depicted above and made as function. It takes an array, the sorting function and a boolean as input:
function schwartzianSort(array,f,asc){
for (var i=array.length;i;){
var o = array[--i];
array[i] = [].concat(f.call(o,o,i),o);
}
array.sort(function(a,b){
for (var i=0,len=a.length;i<len;++i){
if (a[i]!=b[i]) return a[i]<b[i]?asc?-1:1:1;
}
return 0;
});
for (var i=array.length;i;){
array[--i]=array[i][array[i].length-1];
}
return array;
}
function schwartzianSort(array, f, asc) {
for (var i = array.length; i;) {
var o = array[--i];
array[i] = [].concat(f.call(o, o, i), o);
}
array.sort(function(a, b) {
for (var i = 0, len = a.length; i < len; ++i) {
if (a[i] != b[i]) return a[i] < b[i] ? asc ? -1 : 1 : 1;
}
return 0;
});
for (var i = array.length; i;) {
array[--i] = array[i][array[i].length - 1];
}
return array;
}
arr = []
arr.push({
date: new Date(1494434112806)
})
arr.push({
date: new Date(1494434118181)
})
arr.push({
date: new Date(1494434127341)
})
console.log(JSON.stringify(arr));
arr = schwartzianSort(arr, function(o) {
return o.date
}, false)
console.log("DESC", JSON.stringify(arr));
arr = schwartzianSort(arr, function(o) {
return o.date
}, true)
console.log("ASC", JSON.stringify(arr));
If like me you have an array with dates formatted like YYYY[-MM[-DD]] where you'd like to order more specific dates before less specific ones, I came up with this handy function:
function sortByDateSpecificity(a, b) {
const aLength = a.date.length
const bLength = b.date.length
const aDate = a.date + (aLength < 10 ? '-12-31'.slice(-10 + aLength) : '')
const bDate = b.date + (bLength < 10 ? '-12-31'.slice(-10 + bLength) : '')
return new Date(aDate) - new Date(bDate)
}
Thanks for those brilliant answers on top. I have thought a slightly complicated answer. Just for those who want to compare different answers.
const data = [
'2-2018', '1-2018',
'3-2018', '4-2018',
'1-2019', '2-2019',
'3-2019', '4-2019',
'1-2020', '3-2020',
'4-2020', '1-2021'
]
let eachYearUniqueMonth = data.reduce((acc, elem) => {
const uniqueDate = Number(elem.match(/(\d+)\-(\d+)/)[1])
const uniqueYear = Number(elem.match(/(\d+)\-(\d+)/)[2])
if (acc[uniqueYear] === undefined) {
acc[uniqueYear] = []
} else{
if (acc[uniqueYear] && !acc[uniqueYear].includes(uniqueDate)) {
acc[uniqueYear].push(uniqueDate)
}
}
return acc;
}, {})
let group = Object.keys(eachYearUniqueMonth).reduce((acc,uniqueYear)=>{
eachYearUniqueMonth[uniqueYear].forEach(uniqueMonth=>{
acc.push(`${uniqueYear}-${uniqueMonth}`)
})
return acc;
},[])
console.log(group); //["2018-1", "2018-3", "2018-4", "2019-2", "2019-3", "2019-4", "2020-3", "2020-4"]
I have an array of objects in which key 'time' contains the date in ISO format
Example - 2021-12-24T11:02:20.370705
arr.sort(function(a,b){return a.time > b.time ? 1 : a.time < b.time ? -1 : 0 });
Above worked for me like a charm!
If you are into MongoDB, one of the solutions is:
db.collection.find({}).sort("your date field");
For example:
db.collection.find({}).sort("createdAt");