javascript - JavaScript:如何在指定时区获取日期时间
问题描述
有没有办法在 JavaScript 中获取指定时区的本地时间?基本上,我正在寻找一种方式来说明,纽约下午 2 点的 ISO 时间字符串是什么?
我有一个技巧,其中date
是可解析的日期字符串,并且tz
是时区标识符,例如America/New_York
.
function getDateInTZ(date, tz) {
const formatter = new Intl.DateTimeFormat([], {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
fractionalSecondDigits: 3,
timeZone: tz,
});
const localDate = new Date(date);
const localDateAtTZ = new Date(formatter.format(localDate));
const tzOffset = localDate.getTime() - localDateAtTZ.getTime();
return new Date(localDate.getTime() + tzOffset);
}
它具有以下行为
getDateInTz("2021-07-01 20:05", "America/Chicago").toISOString(); // 2021-07-02T01:05:00.000Z
getDateInTz(new Date("2021-12-05 20:05"), "America/Chicago").toISOString(); // 2021-12-06T02:05:00.000Z
getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T02:05:00.000Z if local time is NY
getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T07:05:00.000Z if local time is UTC
虽然上述解决方案适用于 Chrome,但它不适用于 Firefox,因为 FF 无法Date.parse
对formatter.format()
. 这让我认为这不是一个正确的解决方案。
有没有人遇到过这个要求,并且有一个好的解决方案?
解决方案
我们在这里受到 JavaScript 原生 Date 对象的限制。
Date 对象的内部状态是自 1970 年 1 月 1 日 00:00 UTC 以来经过的毫秒数,并且没有时区存储在 Date 对象中。
因此,我们可以创建与在另一个时区创建的日期有点等价的日期,但它们的行为不会完全相同:
Date.toString() 的时区偏移量将显示本地客户端时区(例如 GMT+0000),而不是所需时区的偏移量。
DST 规则可能无法按预期工作。我们可以得到相同的日期,比如 America/New_York,但 DST 转换将遵守当地时区规则,而不是纽约规则。
话虽如此,您使用的方法的一种变体将在所需的时区给出我所说的等效日期。
我们如何做到这一点:
首先使用Date.toLocaleString()在所需时区格式化 ISO 时间戳。我们使用 hack 来做到这一点,将“sv”语言环境传递给函数。这将创建一个 ISO 时间戳,例如 yyyy-MM-dd HH:mm:ss。
将此时间戳传递给 Date() 构造函数。
TLDR:这真的做不到。但是对于某些上下文和用例,我们可以近似期望的行为。为此,我建议使用像luxon这样的库。
下面的例子:
function getDateInTimezone(date, timeZone) {
// Using a locale of 'sv' formats as an ISO date, e.g. yyyy-MM-dd HH:mm.
const timeInTimeZone = date.toLocaleString('sv', { timeZone } );
// Pass this to the Date constructor
return new Date(timeInTimeZone);
}
const localTime = new Date();
const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];
console.log(`Local Time: ${localTime.toLocaleTimeString()}`);
for(let timeZone of timeZoneList) {
const dt = getDateInTimezone(localTime, timeZone);
console.log(`Time (${timeZone}): ${dt.toLocaleTimeString()}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
luxon中的时区更容易处理,当我们在 Luxon DateTime 上调用 .toString() 时,我们会得到正确的 UTC 偏移量。
const { DateTime } = luxon;
const localTime = DateTime.now();
const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];
console.log(`Local Time: ${localTime.toFormat('HH:mm:ssZZ')}`);
for(let zone of timeZoneList) {
const dt = DateTime.fromMillis(Date.now(), { zone });
console.log(`Time (${zone}): ${dt.toFormat(' HH:mm:ssZZ')}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.0.2/luxon.min.js" integrity="sha512-frUCURIeB0OKMPgmDEwT3rC4NH2a4gn06N3Iw6T1z0WfrQZd7gNfJFbHrNsZP38PVXOp6nUiFtBqVvmCj+ARhw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
推荐阅读
- c# - 如何转换列表中的var?
- reactjs - 自定义 Hook:如何在组件卸载时不调用测试集状态
- arrays - 如何在 iOS Swift 的 didselect 方法中重新排列单元格?
- docker - Docker:仅在重新启动时重新启动容器?
- ionic-framework - Ionic - 在 iOS 13 上调用 textElement.focus() 时键盘未打开
- php - 如何在 PHP 中创建这个 JSON?
- google-apps-script - 将 Google 表格同步到日历应用脚本
- npm - 如何使用 npm-uninstall 一次卸载多个插件?
- apache - 子文件夹的htaccass子域重定向问题
- python - 使用 Python 代码执行 Google 搜索