如何将 JavaScript 日期初始化为特定时区

2022-08-29 23:04:29

我将特定时区的日期时间作为字符串,我想将其转换为本地时间。但是,我不知道如何在 Date 对象中设置时区。

例如,我有那么我可以Feb 28 2013 7:00 PM ET,

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);  

据我所知,我可以设置UTC时间或本地时间。但是,如何在其他时区设置时间?

我试图使用UTC的加/减偏移量,但我不知道如何抵消夏令时。我不确定我是否朝着正确的方向前进。

如何在javascript中将时间从不同的时区转换为本地时间?


答案 1

背景

JavaScript 的对象在内部以 UTC 格式跟踪时间,但通常接受输入,并在运行它的计算机的本地时间生成输出。它几乎没有其他时区处理时间的设施。Date

对象的内部表示是一个数字,表示自 以来经过的毫秒数,而不考虑闰秒。Date1970-01-01 00:00:00 UTC

Date 对象本身中没有存储任何时区或字符串格式。

当使用对象的各种功能时,计算机的本地时区将应用于内部表示。如果该函数生成字符串,则可以考虑计算机的区域设置信息,以确定如何生成该字符串。细节因函数而异,有些是特定于实现的。Date

该对象可以对非本地时区执行的唯一操作是:Date

  • 它可以分析包含来自任何时区的数字 UTC 偏移量的字符串。它使用它来调整正在解析的值,并存储 UTC 等效项。原始本地时间和偏移量不会保留在生成的对象中。例如:Date

      var d = new Date("2020-04-13T00:00:00.000+08:00");
      d.toISOString()  //=> "2020-04-12T16:00:00.000Z"
      d.valueOf()      //=> 1586707200000  (this is what is actually stored in the object)
    
  • 在已实现 ECMASCript 国际化 API(也称为“Intl”)的环境中,对象可以生成特定于区域设置的字符串,该字符串已调整为给定的时区标识符。这是通过选项 to 及其变体实现的。大多数实现将支持 IANA 时区标识符,例如 .例如:DatetimeZonetoLocaleString'America/New_York'

      var d = new Date("2020-04-13T00:00:00.000+08:00");
      d.toLocaleString('en-US', { timeZone: 'America/New_York' })
      //=> "4/12/2020, 12:00:00 PM"
      // (midnight in China on Apring 13th is noon in New York on April 12th)
    

    大多数现代环境都支持全套 IANA 时区标识符(请参阅此处的兼容性表)。但是,请记住,Intl 支持的唯一标识符是 ,因此您应该仔细检查是否需要支持较旧的浏览器或非典型环境(例如,轻量级 IoT 设备)。'UTC'

图书馆

有几个库可用于处理时区。虽然他们仍然无法使对象的行为有任何不同,但他们通常实现标准的IANA时区数据库,并提供在JavaScript中使用它的函数。现代库使用由 Intl API 提供的时区数据,但较旧的库通常具有开销,尤其是在 Web 浏览器中运行时,因为数据库可能会变得有点大。其中一些库还允许您有选择地减少数据集,无论是按支持的时区和/或按您可以使用的日期范围。Date

以下是要考虑的库:

基于国际的图书馆

新开发应从以下实现之一中进行选择,这些实现依赖于 Intl API 作为其时区数据:

非国际图书馆

这些库是维护的,但承担了打包自己的时区数据的负担,这些数据可能相当大。

*虽然之前推荐了Moment和Moment-Timezone,但Moment团队现在更喜欢用户选择Luxon进行新的开发。

已停产的图书馆

这些图书馆已正式停产,不应再使用。

未来提案

TC39 时态提案旨在提供一组新的标准对象,用于在 JavaScript 语言本身中处理日期和时间。这将包括对时区感知对象的支持。


答案 2

正如马特·约翰逊所说

如果可以将使用限制为现代 Web 浏览器,则现在可以在没有任何特殊库的情况下执行以下操作:

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})

这不是一个全面的解决方案,但它适用于许多只需要输出转换(从UTC或本地时间到特定时区,但不需要另一个方向)的方案。

因此,尽管浏览器在创建日期时无法读取IANA时区,或者有任何方法可以更改现有Date对象上的时区,但似乎有一个黑客围绕它:

function changeTimezone(date, ianatz) {

  // suppose the date is 12:00 UTC
  var invdate = new Date(date.toLocaleString('en-US', {
    timeZone: ianatz
  }));

  // then invdate will be 07:00 in Toronto
  // and the diff is 5 hours
  var diff = date.getTime() - invdate.getTime();

  // so 12:00 in Toronto is 17:00 UTC
  return new Date(date.getTime() - diff); // needs to substract

}

// E.g.
var here = new Date();
var there = changeTimezone(here, "America/Toronto");

console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);