如何按日期(ISO 8601)对此数组进行排序?
var myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
如何按日期(ISO 8601)对此数组进行排序?
var myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
正如 @kdbanman 指出的那样,ISO8601见一般原则是为了字典排序而设计的。因此,ISO8601字符串表示形式可以像任何其他字符串一样进行排序,这将给出期望的顺序。
'2007-01-17T08:00:00Z' < '2008-01-17T08:00:00Z' === true
那么你需要实现:
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }
];
myArray.sort(function(a, b) {
return (a.date < b.date) ? -1 : ((a.date > b.date) ? 1 : 0);
});
旧版本的WebKit和Internet Explorer不支持ISO 8601日期格式,因此您需要创建一个兼容的日期。它被FireFox和现代WebKit支持有关Date.parse支持的更多信息,请参见JavaScript:哪些浏览器支持使用Date.parse解析ISO-8601日期字符串
这是一篇非常好的文章,用于创建JavaScript ISO 8601兼容日期,然后您可以像普通JavaScript日期一样进行排序。
http://webcloud.se/log/JavaScript-and-ISO-8601/
Date.prototype.setISO8601 = function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
}
使用方法:
console.log(myArray.sort(sortByDate));
function sortByDate( obj1, obj2 ) {
var date1 = (new Date()).setISO8601(obj1.date);
var date2 = (new Date()).setISO8601(obj2.date);
return date2 > date1 ? 1 : -1;
}
更新用法以包括排序技术信用@nbrooks
?:
复合运算符或其他表达式来避免创建日期:
var myArray = [
{name: 'oldest', date: '2007-01-17T08:00:00Z'},
{name: 'newest', date: '2011-01-28T08:00:00Z'},
{name: 'old', date: '2009-11-25T08:00:00Z'}
];
// Oldest first
console.log(
myArray.sort((a, b) => a.date.localeCompare(b.date))
);
// Newest first
console.log(
myArray.sort((a, b) => -a.date.localeCompare(b.date))
);
请注意,现在被接受的答案建议按字典顺序排序日期。
然而,这只有在所有字符串使用“Z”或“+00”时区(= UTC)时才有效。 以“Z”结尾的日期字符串确实符合ISO8601标准,但并非所有ISO8601都以“Z”结尾。
因此,为了完全符合ISO8601标准,您需要使用某个日期库(例如Javascript Date或Moment.js)解析您的字符串,并比较这些对象。 关于此部分,您可以查看Scott的答案,它还涵盖了与ISO8601不兼容的浏览器。
我的简单示例使用Javascript Date(适用于任何不太旧的浏览器):
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00+0100' },
{ name:'old', date:'2009-11-25T08:00:00-0100' }
];
myArray.sort(function(a, b) {
return new Date(a.date) - new Date(b.date);
});
缺点:这比仅按字典顺序比较字符串要慢。
关于ISO8601标准的更多信息:在此处。
const myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
function byDate (a, b) {
if (a.date < b.date) return -1;
if (a.date > b.date) return 1;
return 0;
}
const newArray = myArray.sort(byDate);
console.clear();
console.dir(myArray);
console.dir(newArray);
$(document).ready(function()
{
var myArray = [ { name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }];
console.log( myArray.sort(sortByDate) );
});
// Stable, ascending sort (use < for descending)
function sortByDate( obj1, obj2 ) {
return new Date(obj2.date) > new Date(obj1.date) ? 1 : -1;
}
'2007-01-17T08:00:00Z' < '2008-01-17T08:00:00Z' === true
。请参见下面的@rjmunro答案。 - kdbanmanvar myArray = new Array();
myArray[0] = { name:'oldest', date: '2007-01-17T08:00:00Z' };
myArray[1] = { name:'newest', date: '2011-01-28T08:00:00Z' };
myArray[2] = { name:'old', date: '2009-11-25T08:00:00Z' };
var sortFunction = function (a, b) {
return Date.parse(b.date) - Date.parse(a.date);
};
/* or
var sortFunction = function (a, b) {
return new Date(b.date) - new Date(a.date);
};
*/
console.log(myArray.sort(sortFunction));
ISO8601旨在以纯文本的形式正确排序,因此通常情况下,普通排序就可以了。
要按数组中对象的特定键进行排序,您需要为sort()
方法指定比较函数。在许多其他语言中,这些很容易使用cmp
函数编写,但JS没有内置的cmp
函数,因此我发现编写自己的函数最容易。
var myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
// cmp helper function - built in to many other languages
var cmp = function (a, b) {
return (a > b) ? 1 : ( (a > b) ? -1 : 0 );
}
myArray.sort(function (a,b) { return cmp(a.date, b.date) });
顺便说一下,我会使用类似JSON的语法来编写我的数组,就像这样:
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }
];
如果您正在对可能缺少日期且日期可能处于不同时区的对象进行排序,则最终需要使用更复杂的内容:
const deletionDateSortASC = (itemA, itemB) =>
(+new Date(itemA.deletedAt) || 0) -
(+new Date(itemB.deletedAt) || 0);
const deletionDateSortDESC = (itemA, itemB) =>
deletionDateSortASC(itemB, itemA);
如果你知道日期都有定义且有效,并且你知道所有日期都在同一个时区,那么你应该选择其他更快的答案之一。然而,如果你想要进行日期排序,有一个或多个这些边缘情况,并且不想预处理数据来清理它,那么我建议使用这种方法。
我尝试在下面的代码片段中演示了其他答案在这些边缘情况下的失败。
const data = [
{deletedAt: null},
{deletedAt: '2022-08-24T12:00:00Z'},
{deletedAt: undefined},
{deletedAt: '2015-01-01T00:00:00Z'},
{deletedAt: '2022-08-24T12:00:00-01:00'},
{deletedAt: '2022-08-24T12:00:00+01:00'},
{deletedAt: '2022-08-20T12:00:00+01:00'},
{deletedAt: undefined}
];
const deletionDateSortASC = (itemA, itemB) =>
(+new Date(itemA.deletedAt) || 0) -
(+new Date(itemB.deletedAt) || 0);
const deletionDateSortDESC = (itemA, itemB) =>
deletionDateSortASC(itemB, itemA);
function acceptedAnswerSortASC(a, b) {
return (a.deletedAt < b.deletedAt) ? -1 : ((a.deletedAt > b.deletedAt) ? 1 : 0);
}
function acceptedAnswerSortDESC(a, b) {
return acceptedAnswerSortASC(b, a);
}
// Had to modify this solution to avoid the TypeError: a.deletedAt is null
const localeCompareSortASC = (a, b) => (a.deletedAt || '').localeCompare(b.deletedAt);
const localeCompareSortDESC = (a, b) => -(a.deletedAt || '').localeCompare(b.deletedAt);
function simpleDateSubtractionSortASC(a, b) {
return new Date(a.deletedAt) - new Date(b.deletedAt);
}
function simpleDateSubtractionSortDESC(a, b) {
return simpleDateSubtractionSortASC(b, a);
}
console.log('Using modified Date subtraction', [...data].sort(deletionDateSortDESC));
console.log('Using accepted answer lexocographical sort', [...data].sort(acceptedAnswerSortDESC));
console.log('Using locale compare lexocographical sort', [...data].sort(localeCompareSortDESC));
console.log('Using simple Date subtraction sort', [...data].sort(simpleDateSubtractionSortDESC));
Date.parse
,但它不能给出一致的结果。https://dev59.com/lW025IYBdhLWcg3wyJCV - Scott