按 ISO 8601 日期对数组进行排序

IT技术 javascript arrays sorting iso8601
2021-02-05 00:50:50

我如何按日期排序这个数组(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' }

游乐场:http :
//jsfiddle.net/4tUZt/

提前致谢!

6个回答

按字典排序:

正如@kdbanman 指出的那样,ISO8601 See一般原则是为字典排序而设计的。因此,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);
});

使用 JavaScript 日期排序:

旧版本的 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

我发现在底部返回它 Date.prototype.setISO8601 = function (string) { ... return this; } 是完成这项工作所必需的......
2021-03-19 00:50:50
这可能是完整的,但这是不必要的。 ISO8601 是为字典排序而设计的,所以只要'2007-01-17T08:00:00Z' < '2008-01-17T08:00:00Z' === true
2021-03-27 00:50:50
小心,这个答案并不完全正确。正如@icoum 所指出的,如果您的 ISO8601 日期字符串包含时区偏移量或 - 不太常见 - 负年份,则字典排序不起作用。因此,如果您不能 100% 确定所有日期都是在通用时间中给出的,您绝对应该首先从您的 iso 字符串创建日期对象,然后比较日期对象。
2021-03-27 00:50:50
在 sort 函数中,当你返回 1、-1 和 0 时会发生什么?
2021-04-06 00:50:50
@kdbanman 谢谢,很高兴知道。我已经更新了答案以包含此内容。
2021-04-12 00:50:50

您可以避免创建日期并使用内置的字典比较函数String.prototype.localeCompare,而不是?:复合运算符或其他表达式:

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 DateMoment.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 标准的更多信息:此处

这是一个很好的观点,但这是一个不寻常的情况(或错误),其中 API 将返回不同格式的日期字符串
2021-04-08 00:50:50
嗨,我不得不不同意。例如,在 Web 应用程序中,您可以比较从 API 获得的某个日期和您刚刚在 Web 应用程序中选择的某个日期。第二个肯定会使用计算机的本地时区,这可能与 API 的不同。您还可以比较从使用不同时区的 2 个不同 API 获得的日期。
2021-04-10 00:50:50

我会这样做:

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);
实际上,在这种情况下,他只是按字母顺序排序,这看起来确实应该起作用 +1
2021-03-23 00:50:50
英雄所见略同。像往常一样,我应该发布答案而不是评论......
2021-03-24 00:50:50
@mplungjan 是的:-) 我也更喜欢干净简单的解决方案,而不是难以阅读和维护过于复杂的问题。
2021-04-03 00:50:50
@Scott 我只是排序字符串而不是日期。这有效,我已经使用了一段时间了。
2021-04-11 00:50:50

http://jsfiddle.net/4tUZt/2/

$(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;
}

@mplungjan 我的直接反应是“那行不通”……但仔细想想,我想不出反例。也许它会奏效。我想无论如何坚持使用日期格式总是更安全......处理缩写版本或不严格遵循标准的API
2021-03-15 00:50:50
@scott 很高兴知道,我不确定 IE 的哪些版本实际上支持它,我会仔细检查。
2021-03-19 00:50:50
只对字符串排序怎么样?
2021-03-24 00:50:50
如果字符串是一致的,它肯定会胜过必须通过箍运行以使其适用于不喜欢该格式的浏览器
2021-03-27 00:50:50
旧版本的 WebKit 和 Internet Explorer 本身不支持 ISO 8601。所以这在旧浏览器中可能会失败。
2021-04-14 00:50:50