如何在JavaScript中输出ISO 8601格式的字符串?


247

我有一个Date对象。如何呈现title以下片段的一部分?

<abbr title="2010-04-02T14:12:07">A couple days ago</abbr>

我有另一个图书馆的“相对语言时间”部分。

我尝试了以下方法:

function isoDate(msSinceEpoch) {

   var d = new Date(msSinceEpoch);
   return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T' +
          d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();

}

但这给了我:

"2010-4-2T3:19"

Answers:


453

已经有一个名为的函数toISOString()

var date = new Date();
date.toISOString(); //"2011-12-19T15:28:46.493Z"

如果以某种方式您在不支持它的浏览器上,那么我可以满足您的要求:

if ( !Date.prototype.toISOString ) {
  ( function() {

    function pad(number) {
      var r = String(number);
      if ( r.length === 1 ) {
        r = '0' + r;
      }
      return r;
    }

    Date.prototype.toISOString = function() {
      return this.getUTCFullYear()
        + '-' + pad( this.getUTCMonth() + 1 )
        + '-' + pad( this.getUTCDate() )
        + 'T' + pad( this.getUTCHours() )
        + ':' + pad( this.getUTCMinutes() )
        + ':' + pad( this.getUTCSeconds() )
        + '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
        + 'Z';
    };

  }() );
}

1
.toISOString()绝对以UTC返回日期?
乔恩·威尔斯

new Date("xx").toISOString()产生NaN-NaN-NaNTNaN:NaN:NaN.NZ本机实现引发RangeException。
Joseph Lennox

如果您想将日期对象传递给肥皂服务...就是这样!:) 谢谢。
thinklinux 2014年

1
在OP提供的示例中,没有毫秒或时区。
Dan Dascalescu

所有这些函数调用(例如“ getUTCFullYear”)都将失败,因为IE文档模式5并不知道它们
。– Elaskanator

63

请参阅第https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference:Global_Objects:Date页面上的最后一个示例:

/* Use a function for the exact format desired... */
function ISODateString(d) {
    function pad(n) {return n<10 ? '0'+n : n}
    return d.getUTCFullYear()+'-'
         + pad(d.getUTCMonth()+1)+'-'
         + pad(d.getUTCDate())+'T'
         + pad(d.getUTCHours())+':'
         + pad(d.getUTCMinutes())+':'
         + pad(d.getUTCSeconds())+'Z'
}

var d = new Date();
console.log(ISODateString(d)); // Prints something like 2009-09-28T19:03:12Z

1
OP(<abbr title="2010-04-02T14:12:07">)提供的样本没有时区。也许他们想要本地时间,这对于UI时间字符串有意义吗?
Dan Dascalescu

60

网络上几乎所有的to-ISO方法都通过在输出字符串之前将转换应用于“ Z” ulu时间(UTC)来丢弃时区信息。浏览器的本机.toISOString()也会删除时区信息。

这会丢弃有价值的信息,因为服务器或收件人可以始终将完整的ISO日期转换为Zulu时间或所需的任何时区,同时仍能获取发送者的时区信息。

我遇到的最好的解决方案是使用Moment.js javascript库并使用以下代码:

获取带有时区信息和毫秒的当前ISO时间

now = moment().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T20:11:11.234+0100"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T19:11:11.234+0000"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss") + "Z"
// "2013-03-08T19:11:11Z" <- better use the native .toISOString() 

获取带有时区信息但不带毫秒的本地JavaScript Date对象的ISO时间

var current_time = Date.now();
moment(current_time).format("YYYY-MM-DDTHH:mm:ssZZ")

可以将其与Date.js结合使用,以获取类似Date.today()的函数,然后将其结果传递给一下。

像这样格式化的日期字符串是JSON兼容的,很适合存储在数据库中。Python和C#似乎很喜欢。


21
不要和约会对象在一起。只需使用moment.js并保存头发即可。
Valamas

1
实际上,在python和db上,事实证明这很痛苦。db使用UTC(没有问题,因为您可以轻松地转换为UTC服务器端),因此,如果要保留偏移量信息,则需要另一个字段。而且Python更喜欢使用纳秒而不是javascript的毫秒,这通常已经足够了,并且比普通秒更可取。在python上,只有dateutil.parser.parse可以正确地对其进行解析,而要写入毫秒级的ISO,则需要一个“ _when = when.strftime(”%Y-%m-%dT%H:%M:%S.%f%z “);返回_when [:-8] + _when [-5:]”,将nanos转换为毫。不好
Daniel F

3
实际上,您可以像这样省略格式:moment(new Date()).format()。“从1.5.0版开始,不带格式的调用moment#format将默认为... ISO8601格式YYYY-MM-DDTHH:mm:ssZ”。Doc:从momentjs.com/docs/#/displaying/fromnow
user193130 2014年

1
@ user193130很不错,但是您确实需要小心,因为输出不同于本机方法。 moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
奥尔加2015年

1
也许有些挑剔,但这些示例返回的是UTC的当前偏移量,而不是时区。时区是通常表示为“美国/多伦多”的地理区域。许多时区每年两次更改其UTC偏移量,并且不能(总是)从当前UTC偏移量确定时区...因此,此答案也删除了时区信息:-)
Martin Fido

27

问的问题是ISO格式降低精度。瞧:

 new Date().toISOString().slice(0, 19) + 'Z'
 // '2014-10-23T13:18:06Z'

假设需要尾随的Z,否则就忽略它。


14

最短,但不受Internet Explorer 8和更早版本支持:

new Date().toJSON()

12

如果您不需要支持IE7,则以下是一个很好的简洁技巧:

JSON.parse(JSON.stringify(new Date()))

对于IE7,如果包含json3-library(bestiejs.github.io/json3),则此决定也适用。谢谢:)
vladimir

在IE8中也失败。(“'JSON'是未定义的”)
Cees Timmerman 2013年

1
通过JSON来回访问很难看,尤其是当您声明的目标是简洁时;请改用日期的toJSON方法。JSON.stringify无论如何都在使用它。
Mark Amery

@CeesTimmerman IE8支持该JSON对象,尽管在某些兼容模式下不支持。见stackoverflow.com/questions/4715373/...
马克·阿梅里奥

3
在什么方面比这更好.toISOString()
马丁

7

我通常不希望显示UTC日期,因为客户不喜欢在头上进行转换。要显示本地 ISO日期,请使用以下功能:

function toLocalIsoString(date, includeSeconds) {
    function pad(n) { return n < 10 ? '0' + n : n }
    var localIsoString = date.getFullYear() + '-'
        + pad(date.getMonth() + 1) + '-'
        + pad(date.getDate()) + 'T'
        + pad(date.getHours()) + ':'
        + pad(date.getMinutes()) + ':'
        + pad(date.getSeconds());
    if(date.getTimezoneOffset() == 0) localIsoString += 'Z';
    return localIsoString;
};

上面的函数省略了时区偏移信息(除非本地时间恰好是UTC),所以我使用下面的函数在单个位置显示本地偏移。如果希望每次都显示偏移量,也可以将其输出附加到上述函数的结果中:

function getOffsetFromUTC() {
    var offset = new Date().getTimezoneOffset();
    return ((offset < 0 ? '+' : '-')
        + pad(Math.abs(offset / 60), 2)
        + ':'
        + pad(Math.abs(offset % 60), 2))
};

toLocalIsoString用途pad。如果需要,它几乎可以像任何pad功能一样工作,但是为了完整起见,这就是我使用的方法:

// Pad a number to length using padChar
function pad(number, length, padChar) {
    if (typeof length === 'undefined') length = 2;
    if (typeof padChar === 'undefined') padChar = '0';
    var str = "" + number;
    while (str.length < length) {
        str = padChar + str;
    }
    return str;
}

3

在“ T”之后缺少“ +”

isoDate: function(msSinceEpoch) {
  var d = new Date(msSinceEpoch);
  return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T'
         + d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();
}

应该这样做。

对于前导零,您可以从这里使用:

function PadDigits(n, totalDigits) 
{ 
    n = n.toString(); 
    var pd = ''; 
    if (totalDigits > n.length) 
    { 
        for (i=0; i < (totalDigits-n.length); i++) 
        { 
            pd += '0'; 
        } 
    } 
    return pd + n.toString(); 
} 

像这样使用它:

PadDigits(d.getUTCHours(),2)

很棒!但是,它不能解决缺少的“ 0”。
James A. Rosen

1
编写一个函数,将整数转换为2个字符的字符串(如果参数小于10,则以'0'开头),然后针对日期/时间的每个部分调用该函数。
dan04'4

3
function timeStr(d) { 
  return ''+
    d.getFullYear()+
    ('0'+(d.getMonth()+1)).slice(-2)+
    ('0'+d.getDate()).slice(-2)+
    ('0'+d.getHours()).slice(-2)+
    ('0'+d.getMinutes()).slice(-2)+
    ('0'+d.getSeconds()).slice(-2);
}

1
在IE5模式下,我必须走这条路,因为这里所有其他答案都使用了不存在的功能。
Elaskanator

3

toISOString的问题在于,它仅将日期时间设置为“ Z”。

ISO-8601还定义了日期时间,其中时区以小时和分钟为单位,格式类似于2016-07-16T19:20:30 + 5:30(时区在UTC之前)和2016-07-16T19:20:30-01 :00(时区在UTC后面)。

我认为使用另一个插件moment.js来完成如此小的任务不是一个好主意,尤其是当您可以用几行代码来获得它时。



    var timezone_offset_min = new Date().getTimezoneOffset(),
        offset_hrs = parseInt(Math.abs(timezone_offset_min/60)),
        offset_min = Math.abs(timezone_offset_min%60),
        timezone_standard;

    if(offset_hrs < 10)
        offset_hrs = '0' + offset_hrs;

    if(offset_min > 10)
        offset_min = '0' + offset_min;

    // getTimezoneOffset returns an offset which is positive if the local timezone is behind UTC and vice-versa.
    // So add an opposite sign to the offset
    // If offset is 0, it means timezone is UTC
    if(timezone_offset_min < 0)
        timezone_standard = '+' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min > 0)
        timezone_standard = '-' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min == 0)
        timezone_standard = 'Z';

    // Timezone difference in hours and minutes
    // String such as +5:30 or -6:00 or Z
    console.log(timezone_standard); 

一旦时区偏移了小时和分钟,就可以追加到datetime字符串。

我在上面写了一篇博客文章:http : //usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes



2

我能够用更少的代码获得下面的输出。

var ps = new Date('2010-04-02T14:12:07')  ;
ps = ps.toDateString() + " " + ps.getHours() + ":"+ ps.getMinutes() + " hrs";

输出:

Fri Apr 02 2010 19:42 hrs

0
function getdatetime() {
    d = new Date();
    return (1e3-~d.getUTCMonth()*10+d.toUTCString()+1e3+d/1)
        .replace(/1(..)..*?(\d+)\D+(\d+).(\S+).*(...)/,'$3-$1-$2T$4.$5Z')
        .replace(/-(\d)T/,'-0$1T');
}

我在某个地方找到了有关Stack Overflow的基础知识(我相信它是其他Stack Exchange代码打高尔夫的一部分),并且我对其进行了改进,使其也可以在Internet Explorer 10或更早版本上使用。这很丑陋,但可以完成工作。


0

用一些糖和现代语法扩展Sean的简洁明了的答案:

// date.js

const getMonthName = (num) => {
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Oct', 'Nov', 'Dec'];
  return months[num];
};

const formatDate = (d) => {
  const date = new Date(d);
  const year = date.getFullYear();
  const month = getMonthName(date.getMonth());
  const day = ('0' + date.getDate()).slice(-2);
  const hour = ('0' + date.getHours()).slice(-2);
  const minutes = ('0' + date.getMinutes()).slice(-2);

  return `${year} ${month} ${day}, ${hour}:${minutes}`;
};

module.exports = formatDate;

然后例如。

import formatDate = require('./date');

const myDate = "2018-07-24T13:44:46.493Z"; // Actual value from wherever, eg. MongoDB date
console.log(formatDate(myDate)); // 2018 Jul 24, 13:44
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.