问题描述
在 Angular 应用程序中,我有一个表单,我希望用户能够在任何时区创建日期。 用户输入:
- 日期:
20/09/2021
- 小时:
10:30
- 时区(选择):
Europe/Madrid
我所做的是将时区与其偏移量(Europe/Madrid
-> +0200
)之间的关系保存在本地文件中,然后使用字符串创建日期,如下所示:new Date("2021-09-20T10:30:00+0200")
.
我的问题是计算夏令时,现在我使用静态时区,但这不现实,因为有些国家/地区每年更改两次时区。我需要一个自动解决方案。
我一直在阅读有关 moment 和 moment-timezone 的文章,但它们都是遗留项目,不鼓励使用它,所以我正在寻找不同的东西。谢谢。
解决方法
我终于找到了解决方案。
我使用 IANA 代码(例如 Asia/Kabul
)代替静态时区偏移,以便我可以实时计算其值(GMT+4:30
-> +0430
)。
1 - 从 IANA 区域标识符获取时区偏移
我用过 Intl,用于格式化日期的本机浏览器类。示例:
new Intl.DateTimeFormat("en",{
timeZone: "Pacific/Palau",day: "2-digit",month: "2-digit",year: "numeric",weekday: "long",hour: "2-digit",minute: "2-digit",hour12: false,second: "2-digit",timeZoneName: "short",}).format(new Date());
("Thursday,07/15/2021,17:19:51 PM GMT+9");
有了这个我可以创建日期,但日期构造函数将使用本地时区偏移量并计算差异,因此所选时区中的最终时间将不是指定的时间。
2 - 从字符串中获取时区
从 Intl 返回的日期字符串 ("Thursday,17:19:51 PM GMT+9"
) 我得到最后一部分 (GMT+9
),如下所示:
const dateSplit = dateStr.split(" ");
const timezoneAbbr = dateSplit[dateSplit.length - ONE];
3 - 将非标准时区缩写映射到其偏移量
现在,由于一些国家/地区没有标准的时区缩写(如 AST),我们需要在创建 Date
对象之前将 time zone abbreviations 映射到 UTC(因为 Date
构造函数为某些时区缩写返回错误)。我使用这样的枚举创建了这种关系:
export enum TimezoneAbbreviation {
ACDT = '+1030',ACST = '+0930',ACT = '-0500',ADT = '-0300',
4 - 创建日期
最后创建格式为 yyyy/MM/dd hh:mm ZZ
的日期字符串(例如:2021/05/10 10:30 UTC-1
)并用它调用 Date
构造函数。
警告
There's no consensus on timezone abbreviations 并且可能会有所不同(他们使用 CLDR format)。还有一些令人困惑的数据,如重复的缩写:
缩写 | 姓名 | UTC 偏移量 |
---|---|---|
AST | 阿拉伯标准时间 | UTC+03 |
AST | 大西洋标准时间 | UTC−04 |
SST | 萨摩亚标准时间 | UTC−11 |
SST | 新加坡标准时间 | UTC+08 |