【问题标题】:Working with different timezones in Javascript在 Javascript 中使用不同的时区
【发布时间】:2021-09-30 23:51:08
【问题描述】:

我正在为世界各地的用户开发一个基于云的应用程序,该应用程序广泛处理日期和时间值。

考虑一个场景,在 JavaScript 中,我的机器在印度 (GMT+05:30),我必须显示在加利福尼亚时区 (GMT-08:00) 运行的时钟。

在这种情况下,我必须得到一个新的日期对象,

let india_date = new Date()

添加它的时区偏移值,

let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()

添加加利福尼亚的时区偏移值,

let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()

最后是日期对象。

let california_date: Date = new Date(california_ms)

有没有办法直接处理这些类型的时区,而不必一次又一次地转换值?

【问题讨论】:

标签: javascript date datetime timezone


【解决方案1】:

首先,让我们谈谈您问题中的代码。

let india_date = new Date()

您已将此变量命名为 india_date,但只有在设置为印度时区的计算机上运行代码时,Date 对象才会反映印度。如果它在具有不同时区的计算机上运行,​​它将反映该时区。请记住,在内部,Date 对象仅跟踪基于 UTC 的时间戳。当调用需要本地时间的函数和属性时应用本地时区 - 而不是在创建 Date 对象时。

添加它的时区偏移值

let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()

这种方法是不正确的。 getTime() 已经返回基于 UTC 的时间戳。您不需要添加本地偏移量。 (另外,缩写是 UTC,而不是 UTS。)

现在添加加利福尼亚的时区偏移值

let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()

同样,添加偏移量是不正确的。此外,与印度不同,加利福尼亚州采用夏令时,因此一年中的部分时间偏移量为 480 (UTC-8),部分时间偏移量为 420 (UTC-7)。任何函数(例如您的 getCaliforniatimezoneOffsetMS)都需要将时间戳作为参数传入才能生效。

最后是日期对象

let california_date: Date = new Date(california_ms)

Date 构造函数被传递一个数字时间戳时,它必须是UTC。传递这个california_ms 时间戳实际上只是选择了一个不同的时间点。您不能仅通过添加或减去偏移量来更改 Date 对象的行为以使其使用不同的时区。对于任何需要本地时间的函数,例如.toString() 等,它仍将使用其运行所在的本地时区。

这种调整只有一种情况是有意义的,这就是一种称为“时代转移”的技术。调整时间戳以将基本纪元从正常的1970-01-01T00:00:00Z 移开,从而允许利用Date 对象的UTC 函数(例如getUTCHours 等)。问题是:一旦转移,您就不能在该 Date 对象上使用任何本地时间函数,或者将其传递给任何其他期望 Date 对象是正常对象的东西。正确的时代转移是像Moment.js 这样的库的动力。 Here 是正确完成时代转移的另一个例子。

但在您的示例中,您正在移动(两次错误),然后使用 Date 对象,就好像它是正常的而不是移动的一样。这只会导致错误,toString 输出中显示的时区很明显,并且会在本地时区和预期目标时区的任何 DST 转换附近出现数学上的错误。一般来说,您不想采用这种方法。

相反,请阅读我在How to initialize a JavaScript Date to a particular time zone. 上的回答,您的选项列在那里。谢谢。

【讨论】:

  • 嗨@Matt,当部署在美国东部时区(当本地角度应用程序在南亚时区运行时)包含角度项目的天蓝色网络应用程序时,新的 Date() 将发生变化?
  • @anirudhtalluri - 我不知道你在问什么。 Date 对象具有非常明确的行为,这些行为都不取决于您部署应用程序的位置。如果您愿意,请ask a new question 以便您提供支持详细信息。谢谢。
【解决方案2】:

JavaScript Date objects 以 UTC 格式存储日期和时间,但当日期表示为在浏览器本地时区显示日期和时间的文本值时,会自动调用 toString() 方法。因此,当您想要将日期时间转换为本地时间以外的时区时,您实际上是从 UTC 转换为该时区(而不是从您的本地时区转换为另一个时区)。

如果您的用例仅限于特定浏览器并且您可以灵活地格式化(因为浏览器在显示日期字符串格式方面可能会有所不同),那么您也许可以使用 toLocaleString(),但是像 Edge、Android webview 这样的浏览器等不完全支持localesoptions 参数。

以下示例同时设置区域设置和时区,以本地格式输出日期,该格式可能因浏览器而异。

const dt = new Date();
const kolkata = dt.toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' });
const la = dt.toLocaleString('en-US', { timeZone: 'America/Los_Angeles' });
console.log('Kolkata:', kolkata);
// example output: Kolkata: 19/3/2019, 7:36:26 pm
console.log('Los Angeles:', la);
// example output: Los Angeles: 3/19/2019, 7:06:26 AM

您还可以使用Moment.jsMoment Timezone 将日期和时间转换为本地时区以外的时区。例如:

const dt = moment();
const kolkata = dt.tz('Asia/Kolkata').format();
const la = dt.tz('America/Los_Angeles').format();
console.log(kolkata);
// example output: 2019-03-19T19:37:11+05:30
console.log(la);
// example output: 2019-03-19T07:07:11-07:00
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>

【讨论】:

    【解决方案3】:

    嗯,你确实需要随时转换,但它并没有你想象的那么糟糕。

    首先,将所有时间存储为 UTC。可能使用milliseconds format,例如Date.UTC()

    其次,使用存储的信息进行所有操作/比较。

    第三,如果您的基于云的应用程序有一个 API,该 API 也应该只使用 UTC .

    第四,也是最后,只有在 UI 中,您才应该使用您描述的方法或使用诸如 momentjs 之类的库来最终转换为本地日期/时间字符串

    【讨论】:

    • Date.UTC 通常在解析 UTC 时间戳时使用,此处并非如此。它可能适用,但您应该包括如何使用它的示例,因为 OP 似乎不熟悉 Date 对象或它们如何工作,所以只是说使用它并不能回答问题。
    【解决方案4】:

    new Date 创建一个时间值为 UTC 的 Date 对象。如果您可以保证支持 toLocaleStringtimeZone 选项(例如具有受控 SOE 的企业环境),则可以使用它来构建任何时区和任何格式的时间戳,但它可能有点乏味。可能缺乏对一般网络的支持。如果您需要它可靠地工作,那么在这种情况下,图书馆将是首选。

    例如要获取加利福尼亚的值,您可以使用 toLocaleString 和 "America/Los_Angeles" 作为 timeZone 选项:

    var d = new Date();
    
    // Use the default implementation format
    console.log(d.toLocaleString(undefined, {timeZone:'America/Los_Angeles'}));
    
    // Customised format
    var weekday = d.toLocaleString(undefined, {weekday:'long', timeZone:'America/Los_Angeles'});
    var day = d.toLocaleString(undefined, {day:'numeric', timeZone:'America/Los_Angeles'});
    var month = d.toLocaleString(undefined, {month:'long', timeZone:'America/Los_Angeles'});
    var year = d.toLocaleString(undefined, {year:'numeric', timeZone:'America/Los_Angeles'});
    var hour = d.toLocaleString(undefined, {hour:'numeric',hour12: false, timeZone:'America/Los_Angeles'});
    var minute = d.toLocaleString(undefined, {minute:'2-digit', timeZone:'America/Los_Angeles'});
    var ap = hour > 11? 'pm' : 'am';
    hour = ('0' + (hour % 12 || 12)).slice(-2);
    
    console.log(`The time in Los Angeles is ${hour}:${minute} ${ap} on ${weekday}, ${day} ${month}, ${year}`);

    获取时区名称有点困难,没有其他信息很难获取。

    【讨论】:

      猜你喜欢
      • 2021-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 1970-01-01
      • 2017-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多