【发布时间】:2017-09-07 16:29:09
【问题描述】:
背景
我正在为一个项目调查 moment.js 的不同用例,但对秋季结束的夏令时问题感到困惑。在问我的问题之前,由于我想澄清并为有类似问题的其他人提供背景,让我解释一下我在做什么以及春季夏令时的发现。
首先,我正在使用 UTC 时间戳和 America/New_York 时间戳。在美国,2017 年的夏令时开始于 3 月 12 日凌晨 2 点(从凌晨 2:00:00 跳过到凌晨 3:00:00),并在 11 月 5 日凌晨 2 点结束(从凌晨 2:00:00 恢复到凌晨 1:00:00 )。由于我也始终知道需要转换到的目标时区(美国/纽约),因此我不会依赖 moment.js 来检测我的本地时区,而是明确指定我想要的时区。
在夏令时生效的春季,实行夏令时的时区(例如 America/New_York)提前一个小时。 moment.js 处理得很好。
例如,如果我在夏令时对 America/New_York 生效前一秒向 moment.js 传递 UTC 时间戳,它看起来像这样:
moment('2017-03-12T06:59:59Z').tz('America/New_York').format('YYYY/MM/DD hh:mm:ss a z')
由于我的时间戳上的Z,上面的输入被视为UTC,并且我使用.tz('America/New_York') 明确设置目标时区,以便它不使用本地系统时间。
或者使用时刻时区,我可以将输入时区显式设置为 UTC,并将输出设置为 America/New_York。
moment.tz('2017-03-12T06:59:59', 'UTC').tz('America/New_York').format('YYYY/MM/DD hh:mm:ss a z')
无论哪种方式,结果都是2017/03/12 01:59:59 am EST。
然后,我在一秒钟后运行相同的命令片刻。我将只使用上面第一个示例中给出的格式,我将时间指定为 UTC,然后将其转换为 America/New_York 时间:
moment('2017-03-12T07:00:00Z').tz('America/New_York').format('YYYY/MM/DD hh:mm:ss a z')
我的结果与预期的一样正确:2017/03/12 03:00:00 am EDT - 由于夏令时,时间提前了一小时。
然后我可以通过传入 America/New_York 时间戳并将其转换为 UTC 来使用 moment-timezone 以另一种方式返回。
moment.tz('2017-03-12T01:59:59', 'America/New_York').utc().format('YYYY/MM/DD hh:mm:ss a z')
这给了我2017/03/12 06:59:59 am UTC
在 America/New_York 时区的下一个时刻是 03:00:00,因此我将其转换为 UTC...
moment.tz('2017-03-12T03:00:00', 'America/New_York').utc().format('YYYY/MM/DD hh:mm:ss a z')
... 并得到看起来正确的2017/03/12 07:00:00 am UTC。
在美国/纽约时间跳过(“丢失”)一个小时,但时刻可以检测到这一点并将其转换为 UTC。
总之,对于美国的春季夏令时变化,我可以将 UTC 时间戳传递到 moment.js 或 moment-timezone 并在另一个时区取回时间戳,同时应用正确的夏令时偏移量。然后我还可以将 America/New_York 时间戳传递给 moment 并取回正确转换的 UTC 时间戳。
我的问题
太好了,所以我想在秋季夏令时结束时做同样的事情,当然这不是那么简单。我的假设是,由于夏令时有效地导致一个小时“重复”,因此暂时无法知道正确的 UTC 时间。换句话说,夏令时开始时有 1 小时的间隔,现在我们有 1 小时的重叠。
问题(第 1 部分):有没有办法将相对时间戳和时区传递到时刻并取回正确的 UTC 时间?当我在下面的示例中尝试此操作时,UTC 方面的时刻会跳过一个小时。
moment.tz('2017-11-05T01:00:00', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 07:00:00 am UTC"
moment.tz('2017-11-05T01:59:59', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 07:59:59 am UTC"
moment.tz('2017-11-05T02:00:00', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 09:00:00 am UTC"
moment.tz('2017-11-05T02:59:59', 'America/Denver').tz('UTC').format('YYYY/MM/DD hh:mm:ss a z') => "2017/11/05 09:59:59 am UTC"
我认为是因为时间是按时间顺序发生的,如下例所示。没有给出 UTC 偏移上下文,因此我假设时刻无法区分以星号开头的 America/New_York 时间戳:
*2017/11/05 01:00:00 am America/New_York => 2017/11/05 07:00:00 am UTC
*2017/11/05 01:59:59 am America/New_York => 2017/11/05 07:59:59 am UTC
*2017/11/05 01:00:00 am America/New_York => ???
*2017/11/05 01:59:59 am America/New_York => ???
2017/11/05 02:00:00 am America/New_York => 2017/11/05 09:00:00 am UTC
2017/11/05 02:59:59 am America/New_York => 2017/11/05 09:59:59 am UTC
再次,我想知道是否有办法解决这个问题?目前,我拥有的数据中的时间戳不包含 UTC 偏移量。
问题(第 2 部分):如果我在 America/New_York 时区呈现数据,那么认为我将基本上将两个小时的数据点全部塞入从 01 开始的(看似)单个一小时的时间段中是否正确2017 年 11 月 5 日 :00:00 到 01:59:59?
相关主题
关于 SO 的其他一些主题与此相关,但我发现没有一个主题构成或回答相同的问题。我将在这里链接一些以供参考:
【问题讨论】: