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

IT技术 javascript timezone date-formatting
2021-01-20 01:00:54

目标:找到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 晚五个小时。

因此,根据我的理解,我需要通过 new Date() 找到我的本地时间,然后使用 getTimezoneOffset() 函数计算差异,然后将其附加到字符串的末尾。

1.获取本地时间格式

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

输出

2013-07-02T09:00:00

2.按小时获取UTC时间偏移量

var offset = local.getTimezoneOffset() / 60;

输出

7

3.构造URL(仅时间部分)

var duration = local + "-" + offset + ":00";

输出:

2013-07-02T09:00:00-7:00

以上输出表示我的本地时间是 2013/07/02 9am,与 UTC 的时差为 7 小时(UTC 比当地时间提前 7 小时)

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

我想知道在这种情况下格式应该如何,因为我无法从 W3C 文档中弄清楚。提前致谢。

6个回答

这是一个简单的辅助函数,可以为您格式化 JS 日期。

function toIsoString(date) {
  var tzo = -date.getTimezoneOffset(),
      dif = tzo >= 0 ? '+' : '-',
      pad = function(num) {
          var norm = Math.floor(Math.abs(num));
          return (norm < 10 ? '0' : '') + norm;
      };

  return date.getFullYear() +
      '-' + pad(date.getMonth() + 1) +
      '-' + pad(date.getDate()) +
      'T' + pad(date.getHours()) +
      ':' + pad(date.getMinutes()) +
      ':' + pad(date.getSeconds()) +
      dif + pad(tzo / 60) +
      ':' + pad(tzo % 60);
}

var dt = new Date();
console.log(toIsoString(dt));

@tytk - 很棒的收获!这确实是微妙的。我将您的修复添加到了答案中。感谢您的评论!
2021-03-24 01:00:54
@masato-san 您必须反转符号,请参阅developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ 上的定义...
2021-04-06 01:00:54
符号表示当地时间与 GMT 的偏移量
2021-04-07 01:00:54
请注意:此答案中有一个微妙的错误。如果时区偏移量是负数(例如 -09:30),例如法国和加拿大的某些位置,则时区偏移量将无法正确计算。Mod 返回一个负数,因此在 abs() 之前执行 floor() 会无意中使偏移量更负。为了纠正这个错误,所以 abs() 和 THEN floor()。试图编辑答案,但显然“此编辑旨在解决帖子的作者,作为编辑毫无意义”。
2021-04-09 01:00:54
这里 pad 函数为日期的每个部分返回正确的字符串,除了毫秒。例如,作为输入的 5ms 将返回 05,它应该是 005。这是具有相同函数jsbin 的最小修改版本的链接
2021-04-10 01:00:54

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

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

在这种格式中,UTC 用 a 表示,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

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

@AustinFrance - 你说得对!我很惊讶我当时犯了那个错误,因为我经常在这一点上纠正其他人。抱歉我两年前没有看到你的评论!答案已编辑。
2021-03-29 01:00:54
使用 toISOString() 将不起作用。+01:00 格式要求时间部分为当地时间。toISOString() 将给出一个 UTC 时间字符串。
2021-03-31 01:00:54

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

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

// produces "2019-10-30 15:33:47 GMT−4"

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

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

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

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

嗯,对于 sv,我实际上得到了“CET”,而对于夏令时日期,“CEST”...但是感谢您的输入,标准 API 对我来说已经足够了(需要在日志消息前加上日期)。如果我想认真对待时间和时区,我想我会去moment library ......
2021-03-14 01:00:54
加上 'sv' 格式的 toLocaleString
2021-03-31 01:00:54

对于那些只想要本地时区中 YYYY-MM-DD 格式的今天日期的人,我的回答是略有不同。

让我说清楚:

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

这是代码:

new Date().toLocaleDateString("sv") // "2020-02-23" // 

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

无效的答案,这确实可以回答,但其他问题......这个答案可以很容易地在 SO 上找到。
2021-04-03 01:00:54
我还没有完整阅读这个问题,所以我不能说这是否回答了这个问题,但这正是我正在寻找的(而且它非常短)。谢谢!
2021-04-04 01:00:54

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

  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;
  }
@tsh,你确定吗?您正在获取当前时间偏移量,稍后用于模拟本地时间。也许在那个时候偏移量是不同的,但这并不重要,因为你只关心现在。
2021-03-24 01:00:54