首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Javascript日期:为什么我的日期在转换到UTC时使用了错误的时区?

Javascript日期:为什么我的日期在转换到UTC时使用了错误的时区?
EN

Stack Overflow用户
提问于 2022-08-04 17:36:07
回答 2查看 97关注 0票数 0

让我首先描述一下目标。从时间戳开始,我需要将时间转换为UTC时间。那我就得在世界协调时找到午夜。然后我需要找出午夜和时间之间的时间差异。

例如,我有时间戳1793498400153。目标是:

  1. 时间戳1793498400153是2026年10月31日东部夏令时间22:00(我的本地时区)。
  2. 把它转换为UTC时间。2026年11月1日在格林尼治时间02:00。
  3. 找到午夜。午夜是2026年11月1日格林尼治时间00:00。
  4. #2-#3等于2小时。

我喜欢的技术是Javascript日期对象。鲁迅也是可用的,但对于这方面的需要来说太慢了。

当我使用Date对象时,Javascript意外地从夏令时跳到了标准时。

例如:

  1. 将时间戳转换为日期对象。按预期工作。
代码语言:javascript
复制
const dt1 = new Date(1793498400153)
dt1.toString()
// 'Sat Oct 31 2026 22:00:00 GMT-0400 (Eastern Daylight Time)'
  1. 生成一个UTC时间。这不像预期的那样起作用。
代码语言:javascript
复制
const utc = new Date(dt1.getUTCFullYear(), dt1.getUTCMonth(), dt1.getUTCDate(), dt1.getUTCHours(), dt1.getUTCMinutes(), dt1.getUTCSeconds(), dt1.getUTCMilliseconds());
utc.toString()
// 'Sun Nov 01 2026 02:00:00 GMT-0500 (Eastern Standard Time)'

这不是我想要的。我要“格林尼治时间02:00-0400(东部夏令时间)”。

dt1.getUTCHours()返回2

与原始时间戳相比,它确实向前推进了5个小时,而不是4个小时:

代码语言:javascript
复制
(utc.getTime()-dt1.getTime())/3.6e6
// 5

奇怪的是,如果我们在1793498400153之前稍微向后移动时间戳,UTC时间将保持正确的时区。例如:

代码语言:javascript
复制
const dt2 = new Date(1793498399868.3354)
const utc3 = new Date(dt2.getUTCFullYear(), dt2.getUTCMonth(), dt2.getUTCDate(), dt2.getUTCHours(), dt2.getUTCMinutes(), dt2.getUTCSeconds(), dt2.getUTCMilliseconds());
utc3.toString()
'Sun Nov 01 2026 01:59:59 GMT-0400 (Eastern Daylight Time)'

2026年11月2日02:00的时间似乎是UTC时代开始失去DST的神奇时刻。然而,无论是英国还是美国东部都没有改变当时的夏令储蓄。在任何情况下,核心时间戳不应该更改一个额外的小时,以说明差异。

在Chrome和Firefox中都会出现这种情况。

为什么会发生这种情况?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-08-04 19:25:03

首先,回答我自己的问题:为什么时间在2026年11月2日02:00发生了令人惊讶的事情:

等级库呼吁

实现定义的抽象操作LocalTZA接受参数t(一个数字)和isUTC (一个布尔值)并返回一个整数。其返回值表示以毫秒为单位的本地时区调整或偏移。标准时间和夏令时的当地政治规则应在t处使用,以本节规定的方式确定结果。

后来:

建议实现使用IANA时区数据库的时区信息

“时区数据库”实际上是一堆找到这里的压缩文件(并提供令人惊讶的有趣阅读)。该数据库说,对于北美:

代码语言:javascript
复制
# Rule  NAME    FROM    TO  -   IN  ON  AT  SAVE    LETTER/S
...
Rule    US  2007    max -   Nov Sun>=1  2:00    0   S

在11月1日之后的星期日,在02:00,切换到标准时间。果然,2026年11月2日是一个星期一,显然还没有为2026年制定硬性规定,所以使用默认规则。

这个问题来自于我更深层次的误解,那就是,要用UTC时间计算日期数学,需要将分区时间转换为UTC。Javascript原生日期对象在UTC中度量它们的时间戳,因此不需要这样做。遵循ctcpip's引线,这段代码使我达到了我的目标:

代码语言:javascript
复制
const dtNow = Date.now();
const dtMidnight = new Date(dtNow);
dtMidnight.setUTCHours(0, 0, 0, 0);
// 1 hour is 3.6e6 ms
const hrs = (dtNow.getTime() - dtMidnight.getTime()) / 3.6e6;

诀窍是复制原始日期,然后使用setUTCHours在等效的UTC时间上下文中重置小时。

票数 0
EN

Stack Overflow用户

发布于 2022-08-04 18:03:03

在第2步中,您仍然在本地时区中有效地创建Date对象,因为Date构造函数将引用系统的时区解释参数。调用getUTCFullYear()dt1.getUTCMonth()等并不重要,因为它们只是传递给Date构造函数的数字。

你要找的是Date.UTC()

代码语言:javascript
复制
const dt1 = new Date(1793498400153)
dt1.toString()

// 'Sat Oct 31 2026 21:00:00 GMT-0500 (Central Daylight Time)'

const utc = new Date(Date.UTC(dt1.getUTCFullYear(), dt1.getUTCMonth(), dt1.getUTCDate(), dt1.getUTCHours(), dt1.getUTCMinutes(), dt1.getUTCSeconds(), dt1.getUTCMilliseconds()));
utc.toString()

// 'Sat Oct 31 2026 21:00:00 GMT-0500 (Central Daylight Time)'

请记住,Date对象只是表示时间的瞬间;它们实际上没有时区属性。时区偏移量和输出转换仅取决于系统的区域设置。您可以通过实例化Date()对象,然后在更改系统时区之前和之后调用toString()来观察这一点。

完成你想要做的事情:

从时间戳开始,我需要将时间转换为UTC时间。那我就得在世界协调时找到午夜。然后我需要找出午夜和时间之间的时间差异。

代码语言:javascript
复制
// start with a timestamp
const dt1 = new Date(1793498400153)
dt1.toString()

// 'Sat Oct 31 2026 21:00:00 GMT-0500 (Central Daylight Time)'

// there is no need to "convert to UTC time".  output local time with `dt1.toString()` and output UTC time with `dt1.toUTCString()

// get UTC time
dt1.toUTCString()
// 'Sun, 01 Nov 2026 02:00:00 GMT'

// find the difference in hours between midnight and the time

// there are different ways to do this, but an easy way is to just copy the Date and set it to midnight

const dt2 = new Date(dt1);
dt2.setUTCHours(0);

dt2.toUTCString()
// 'Sun, 01 Nov 2026 00:00:00 GMT'

dt1.getTime() - dt2.getTime()
// 7200000
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73240160

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档