如何在JavaScript中使用ISO 8601格式化带有时区偏移的日期?

mas*_*san 90 javascript timezone date-formatting

目标:找到local timeUTC time offset以下列格式构建URL.

示例URL:/ Actions/Sleep?duration = 2002-10-10T12:00:00-05:00

格式基于W3C建议:http: //www.w3.org/TR/xmlschema11-2/#dateTime

文件说:

例如,2002-10-10T12:00:00-05:00(2002年10月10日中午,中央夏令时以及美国东部标准时间)等于2002-10-10T17:00:00Z,比2002-10-10T12:00:00Z晚5个小时.

所以基于我的理解,我需要通过新的Date()找到我的本地时间,然后使用getTimezoneOffset()函数来计算差异,然后将它附加到字符串的末尾.

1.以格式获取当地时间

var local = new Date().format("yyyy-MM-ddThh:mm:ss"); //today (local time)
Run Code Online (Sandbox Code Playgroud)

产量

2013-07-02T09:00:00
Run Code Online (Sandbox Code Playgroud)

2.以小时为单位获取UTC时间偏移量

var offset = local.getTimezoneOffset() / 60;
Run Code Online (Sandbox Code Playgroud)

产量

7
Run Code Online (Sandbox Code Playgroud)

3.Construct URL(仅限时间部分)

var duration = local + "-" + offset + ":00";
Run Code Online (Sandbox Code Playgroud)

输出:

2013-07-02T09:00:00-7:00
Run Code Online (Sandbox Code Playgroud)

以上输出结果表示我的当地时间是2013/07/02 9am,与UTC的差异是7小时(UTC是比当地时间早7小时)

到目前为止它似乎工作,但如果getTimezoneOffset()返回负值如-120怎么办?

我想知道在这种情况下格式应该是什么样的,因为我无法从W3C文档中找到答案.提前致谢.

Ste*_*ley 157

以下应该适用于所有浏览器(感谢@MattJohnson提示)

Date.prototype.toIsoString = function() {
    var tzo = -this.getTimezoneOffset(),
        dif = tzo >= 0 ? '+' : '-',
        pad = function(num) {
            var norm = Math.floor(Math.abs(num));
            return (norm < 10 ? '0' : '') + norm;
        };
    return this.getFullYear() +
        '-' + pad(this.getMonth() + 1) +
        '-' + pad(this.getDate()) +
        'T' + pad(this.getHours()) +
        ':' + pad(this.getMinutes()) +
        ':' + pad(this.getSeconds()) +
        dif + pad(tzo / 60) +
        ':' + pad(tzo % 60);
}

var dt = new Date();
console.log(dt.toIsoString());
Run Code Online (Sandbox Code Playgroud)

  • 请注意:这个答案中有一个微妙的错误.如果区域具有偏移分钟并且为负(例如-09:30),则不会正确计算时区偏移,例如法国和加拿大的某些位置.Mod返回一个负数,因此在abs()之前执行floor()会无意中使偏移量为负数.要纠正这个错误,所以abs()和THEN floor().试图编辑答案,但显然"这个编辑旨在解决帖子的作者,并没有任何意义作为编辑". (8认同)
  • @tytk - 很棒!这确实是微妙的.我在答案中添加了您的修复程序.感谢您的评论! (5认同)
  • @RobG 好点,Math.floor 也是如此。并且......更新了! (3认同)
  • 该符号表示当地时间与GMT的偏移量 (2认同)
  • 这里pad函数为每个日期部分返回正确的字符串,除了毫秒.例如,对于5ms作为输入将返回05,这应该是005.这是一个具有相同功能的最小修改版本的链接[jsbin](https://jsbin.com/poroqiboqi/edit?js,console,输出) (2认同)
  • 谢谢。读完所有的答案后,我仍然惊讶于 javascript 对于某些与日期相关的东西来说是一种“DIY”语言。 (2认同)
  • 这仍然是最好的答案吗?javascript 有没有方法做到这一点?...由第一次必须这样做的人问... (2认同)
  • 你可以使用 padStart 更紧凑一些: `\`${Math.floor(Math.abs(num))}\`.padStart(2, '0')` (2认同)

Mat*_*int 63

getTimezoneOffset() 返回您引用的规范所需格式的相反符号.

这种格式也称为ISO8601,或者更准确地称为RFC3339.

在这种格式中,UTC用一段Z时间表示,所有其他格式由UTC的偏移量表示.含义与JavaScript相同,但减法的顺序是反转的,因此结果带有相反的符号.

此外,在Date调用的本机对象上没有方法format,因此除非您使用库来实现此功能,否则#1中的函数将失败.请参阅此文档.

如果您正在寻找可以直接使用此格式的库,我建议您尝试使用moment.js.实际上,这是默认格式,因此您可以简单地执行此操作:

var m = moment();    // get "now" as a moment
var s = m.format();  // the ISO format is the default so no parameters are needed

// sample output:   2013-07-01T17:55:13-07:00
Run Code Online (Sandbox Code Playgroud)

这是一个经过良好测试的跨浏览器解决方案,并具有许多其他有用的功能.


Tom*_*Tom 24

我认为值得考虑的是,您只需对标准库进行一次 API 调用即可获取请求的信息......

new Date().toLocaleString( 'sv', { timeZoneName: 'short' } );

// produces "2019-10-30 15:33:47 GMT?4"
Run Code Online (Sandbox Code Playgroud)

如果要添加“T”分隔符、删除“GMT-”或将“:00”附加到末尾,则必须进行文本交换。

但是,如果您愿意,您可以轻松地使用其他选项。使用 12h 时间或省略秒等。

请注意,我使用瑞典作为语言环境,因为它是使用 ISO 8601 格式的国家之一。我认为大多数 ISO 国家都使用这种“GMT-4”格式作为时区偏移量,而不是加拿大使用时区缩写,例如。“EDT”表示东部夏令时。

您可以从较新的标准 i18n 函数“Intl.DateTimeFormat()”中获得相同的信息,但您必须通过选项告诉它包含时间,否则它只会给出日期。

  • 请注意,区域设置可能随时更改其首选日期格式。 (8认同)
  • 嗯,对于 sv,我实际上得到“CET”,对于夏季时间日期,“CEST”...但是感谢您的输入,标准 API 对我来说就足够了(需要在日志消息中添加日期前缀)。如果我想认真对待时间和时区,我想我会去 moment 库...... (2认同)
  • @Venryx 根据 ISO 639-1 https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes,sv 代表瑞典语。我敢打赌这是因为他们称他们的语言为斯文斯卡语 (2认同)

Jon*_*ele 10

对于那些只想要 YYYY-MM-DD 格式的本地时区今天日期的人来说,我的回答是一个细微的变化。

让我说清楚:

我的目标:用户的时区中获取今天的日期,但格式为 ISO8601 (YYYY-MM-DD)

这是代码:

new Date().toLocaleDateString("sv") // "2020-02-23" // 
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为瑞典语言环境使用 ISO 8601 格式。

  • 我还没有完整地阅读这个问题,所以我不能说这是否回答了问题,但这正是我正在寻找的(而且它非常短)。谢谢你! (7认同)
  • @KnechtRootrecht:这是语言代码,而不是国家/地区代码。 (2认同)

Bbb*_*Bbb 6

这是我针对客户时区的功能,重量轻且简单

  function getCurrentDateTimeMySql() {        
      var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
      var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, 19).replace('T', ' ');
      var mySqlDT = localISOTime;
      return mySqlDT;
  }
Run Code Online (Sandbox Code Playgroud)


Nah*_*eco 6

检查这个:

function dateToLocalISO(date) {
    const off    = date.getTimezoneOffset()
    const absoff = Math.abs(off)
    return (new Date(date.getTime() - off*60*1000).toISOString().substr(0,23) +
            (off > 0 ? '-' : '+') + 
            Math.floor(absoff / 60).toFixed(0).padStart(2,'0') + ':' + 
            (absoff % 60).toString().padStart(2,'0'))
}

// Test it:
d = new Date()

dateToLocalISO(d)
// ==> '2019-06-21T16:07:22.181-03:00'

// Is similar to:

moment = require('moment')
moment(d).format('YYYY-MM-DDTHH:mm:ss.SSSZ') 
// ==> '2019-06-21T16:07:22.181-03:00'
Run Code Online (Sandbox Code Playgroud)


Ext*_*rey 6

您可以通过一些简单的扩展方法来实现这一点。以下日期扩展方法仅返回 ISO 格式的时区部分,然后您可以为日期/时间部分定义另一个部分,并将它们组合起来形成完整的日期时间偏移字符串。

Date.prototype.getISOTimezoneOffset = function () {
    const offset = this.getTimezoneOffset();
    return (offset < 0 ? "+" : "-") + Math.floor(Math.abs(offset / 60)).leftPad(2) + ":" + (Math.abs(offset % 60)).leftPad(2);
}

Date.prototype.toISOLocaleString = function () {
    return this.getFullYear() + "-" + (this.getMonth() + 1).leftPad(2) + "-" +
        this.getDate().leftPad(2) + "T" + this.getHours().leftPad(2) + ":" +
        this.getMinutes().leftPad(2) + ":" + this.getSeconds().leftPad(2) + "." +
        this.getMilliseconds().leftPad(3);
}

Number.prototype.leftPad = function (size) {
    var s = String(this);
    while (s.length < (size || 2)) {
        s = "0" + s;
    }
    return s;
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

var date = new Date();
console.log(date.toISOLocaleString() + date.getISOTimezoneOffset());
// Prints "2020-08-05T16:15:46.525+10:00"
Run Code Online (Sandbox Code Playgroud)

我知道现在是 2020 年,大多数人现在可能都在使用 Moment.js,但简单的复制和粘贴解决方案有时仍然很方便。

(我拆分日期/时间和偏移方法的原因是因为我使用的是旧的Datejs库,该库已经提供了带有自定义格式说明符的灵活toString方法,但只是不包含时区偏移。因此,我为toISOLocaleString任何没有说图书馆。)