2025 年,是时候彻底搞懂 JavaScript Date 了!

内容分享2个月前发布
4 5 0

1. 时钟时间 (Clock Time) 与准确时间 (Exact Time)

Temporal 的核心概念是依赖于时区的挂钟时间(Wall-clock Time)和准确时间(Exact Time,也称为 UTC Time)的区别。挂钟时间由地方政府机构控制,因此可能会突然改变。

2025 年,是时候彻底搞懂 JavaScript Date 了!

列如:当夏令时 (Daylight Saving Time,DST) 开始或一个国家或地区移至另一个时区时,当地时钟时间 (智能手表、电脑等自动变化,而挂钟需要手动调整) 将立即发生变化。 不过,准确时间具有全球一致的定义,并由称为 UTC 的特殊时区表明。

协调世界时(`Coordinated Universal Time 或 UTC`):是世界规范时钟和时间的主要标准,与经度 0° 、即本初子午线的平均太阳时相差约 1 秒,并且 ` 未根据夏令时进行调整 `,是格林威治标准时间 (GMT) 的继承者。

挂钟时间则使用 UTC 偏移量定义,特定时钟设置在 UTC 之前或之后的准确时间量。 例如,2020 年 1 月 19 日,加利福尼亚州的 UTC 偏移量为 -08:00,这意味着旧金山的挂钟时间比 UTC 晚 8 小时,因此当地时间为上午 10:00 的时候,UTC 时间为当天 18:00 。

ISO 8601 和 RFC 3339 将准确时间的标准表明形式定义为日期和时间值,例如: 2020-09-06T17:35:24.485Z,Z 后缀表明这是准确的 UTC 时间 。

RFC3339 与 ISO8601 的区别:最值得注意的是 RFC 3339 需要日期和时间的完整表明,只有小数秒是可选的,RFC 3339 需要 4 位数的年份,同时只允许使用句点字符作为小数秒的小数点。

Temporal 有两种存储准确时间的类型,包括:

  • Temporal.Instant:仅存储准确时间,不存储其他信息
  • Temporal.ZonedDateTime:存储准确时间、时区和日历系统

表明准确时间的另一种方法是使用 Unix 时间戳,其是 自 1970 年 1 月 1 日午夜 UTC(称为 Unix 纪元)以来经过的秒数,Un 是一个整数(支持正数和负数),一般用于计算机系统中表明时间。 例如,Temporal.Instant(准确时间类型)可以仅使用自纪元以来纳秒的 BigInt 值来构造。

2025 年,是时候彻底搞懂 JavaScript Date 了!

开发人员常常遇到的另一个术语是 “时间戳(timestamp)”,其一般指的是用自 Unix 纪元以来的秒数表明的准确时间 。 不过,由于 “时间戳” 一词在历史上存在歧义,Temporal 已经避免使用该术语。 例如,许多数据库都有一个名为 TIMESTAMP 的类型但含义却各不一样:

  • MySQL 中是一个准确的时间
  • Oracle 数据库中是自 1970 年 1 月 1 日挂钟时间以来的秒数
  • 在 Microsoft SQL Server 中是一个与日期和时间无关的单调递增值。

`Unix 时间戳基于 UTC`,因此 ` 不受时区的影响 `,便于在不同地区的系统之间进行时间比较和计算。

2. 时区(Time Zones)、偏移量变化(Offset Changes)和 DST(Daylight Saving Time)

SDT(Standard Time) 表明标准时间,DST(Daylight Saving Time ) 表明夏令时,从图可知中国没有实现夏令时。

时区(Time Zones)定义了控制本地挂钟时间与 UTC 时间关联方式的规则,可以 将时区视为接受准确时间并返回 UTC 偏移量的函数,以及用于相反方向转换的相应函数。

2025 年,是时候彻底搞懂 JavaScript Date 了!

Temporal 使用 IANA 时区数据库(IANA Time Zone Database),可以将其视为 时区函数的全局存储库, 每个 IANA 时区都有:

  • 时区 ID:一般指由城市锚定的地理区域(例如:Europe/Paris 或 Africa/Kampala 或者 Asia/Shanghai),也可以表明单偏移时区(Single-offset Time Zones),例如: UTC(一致的 +00:00 偏移)或 Etc/GMT+ 5(负偏移 -05:00)。
  • 时区定义(Time Zone Definition):自 1970 年 1 月 1 日以来 UTC 值的偏移量,可以将这些定义视为将 UTC 日期时间映射到特定偏移量的表。 在某些时区,由于夏令时 (DST) 从春季开始到秋季结束,每年会发生 两次临时偏移变化从而抵消,也可能由于政治变化而永久改变,例如,一个国家切换时区。

IANA 时区数据库每年更新几次以响应世界各地的政治变化 ,每次更新都包含对时区定义的更改。 这些 更改一般仅影响未来的日期 / 时间值,但有时也会对过去的范围进行修复,例如:当发现有关 20 世纪早期计时的新历史来源时。下图表明数据库时区列表的部分截图:

3.Temporal 中的挂钟时间、确切时间和时区

Temporal 对象包含以下属性和方法:

  • Temporal.Instant: 表明准确时间。
  • Temporal.PlainDateTime: 类型表明 日历日期和挂钟时间,其他类型也是如此,例如:Temporal.PlainDate、Temporal.PlainTime、Temporal.PlainYearMonth 和 Temporal.PlainMonthDay。 这些类型都带有日历系统,默认情况下为 “iso8601”(ISO 8601 日历),但可以被 “islamic” 或 “japanese” 等其他日历覆盖。
  • Temporal.TimeZone :时区函数,用于在准确时间和挂钟时间之间进行转换,反之亦然。 其还包括辅助函数,例如:获取特定准确时间的当前时区偏移量。
  • Temporal.ZonedDateTime :封装了上述所有类型:准确时间(如 Temporal.Instant)、其挂钟等效项(如 Temporal.PlainDateTime)以及链接两者的时区(如 Temporal.TimeZone) 。

有两种方法可以从存储准确时间的 Temporal 类型获取人类可读的日历日期和时钟时间。

  • 如果确切的时间由 Temporal.ZonedDateTime 表明,则可以使用该类型的属性和方法获得挂钟时间值,例如 .year、.hour 或 .toLocaleString()。
  • 如果确切时间由 Temporal.Instant 表明,则可使用 时区 和 可选日历 来创建 Temporal.ZonedDateTime。

列如下面的示例:

instant = Temporal.Instant.from('2019-09-03T08:34:05Z');
formatOptions = {
  era: 'short',
  year: 'numeric',
  month: 'short',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
};
zdt = instant.toZonedDateTimeISO('Asia/Tokyo');
  // 输出值 => 2019-09-03T17:34:05+09:00[Asia/Tokyo]
zdt.toLocaleString('en-us', { ...formatOptions, calendar: zdt.calendar});
  // 输出值 => 'Sep 3, 2019 AD, 5:34:05 PM'
zdt.year;
  // 输出值 => 2019
zdt = instant.toZonedDateTime({timeZone: 'Asia/Tokyo', calendar: 'iso8601'}).toLocaleString('ja-jp', formatOptions);
  // => 输出值 '西暦 2019 年 9 月 3 日 17:34:05'
zdt = instant.toZonedDateTime({timeZone: 'Asia/Tokyo', calendar: 'japanese'});
  // 输出值  => 2019-09-03T17:34:05+09:00[Asia/Tokyo][u-ca=japanese]
zdt.toLocaleString('en-us', { ...formatOptions, calendar: zdt.calendar});
  // 输出值 => 'Sep 3, 1 Reiwa, 5:34:05 PM'
zdt.eraYear;
  // 输出值 => 1

还支持从 日历日期 和或 挂钟时间 到 准确时间 的转换:

// 通过提供时区将各种本地时间类型转换为准确时间类型
date = Temporal.PlainDate.from('2019-12-17');
// 如果省略时间,则当地时间默认为当天的开始时间
zdt = date.toZonedDateTime('Asia/Tokyo');
  // 输出值 => 2019-12-17T00:00:00+09:00[Asia/Tokyo]
zdt = date.toZonedDateTime({timeZone: 'Asia/Tokyo', plainTime: '10:00'});
  // 输出值 => 2019-12-17T10:00:00+09:00[Asia/Tokyo]
time = Temporal.PlainTime.from('14:35');
zdt = time.toZonedDateTime({timeZone: 'Asia/Tokyo', plainDate: Temporal.PlainDate.from('2020-08-27') });
  // 输出值 => 2020-08-27T14:35:00+09:00[Asia/Tokyo]
dateTime = Temporal.PlainDateTime.from('2019-12-17T07:48');
zdt = dateTime.toZonedDateTime('Asia/Tokyo');
// 输出值 => 2019-12-17T07:48:00+09:00[Asia/Tokyo]
// 获取自 UNIX 纪元以来的准确时间(以秒、毫秒或纳秒为单位)。
inst = zdt.toInstant();
epochNano = inst.epochNanoseconds;
// 输出值 => 1576536480000000000n
epochMilli = inst.epochMilliseconds;
// 输出值 => 1576536480000
epochSecs = inst.epochSeconds;
// 输出值 => 1576536480

4. 导致时钟时间不准确的几个缘由

4.1 时区偏移量 Offset 突变使时钟时间存在二义性

Offset 使得凌晨 3 点时间不再唯一。

时区定义(Time Zone Definition)提供了任何特定本地日期和时钟时间与其相应的 UTC 日期和时间之间的双向 1:1 映射关系,即 UTC 偏移量 Offset 是 UTC 与特定地点时间之间的小时和分钟差异。一般来说,英国以东的时区为 UTC+,英国以西的时区为 UTC-。

2025 年,是时候彻底搞懂 JavaScript Date 了!

不过, 在时区偏移过渡附近(Time Zone Offset Transition) 可能会存在时间模糊性,不清楚应使用什么偏移将挂钟时间转换为准确时间,这种模糊性 可能导致一个时钟时间有两个可能的 UTC 时间。

  • 当偏移量向后变化时,一样的时钟时间将重复: 例如:2018 年 11 月 4 日星期日凌晨 1:30 在加利福尼亚州发生了两次。 该日期的 “第一个” 凌晨 1:30 是太平洋夏令时间(偏移量 -07:00)。 30 分钟后,夏令时结束,太平洋标准时间(偏移量 -08:00)开始生效。 又过了 30 分钟,“第二个” 凌晨 1:30 发生了。 这意味着 “2018 年 11 月 4 日星期日 1:30AM” 不足以知道目前是哪一个凌晨 1:30,即时钟时间不明确。
  • 当偏移向前改变时,本地时钟时间将被跳过: 例如,加利福尼亚州于 2018 年 3 月 11 日星期日开始实行夏令时。 当时钟从凌晨 1:59 前进到凌晨 2:00 时,当地时间立即跳至凌晨 3:00,即凌晨 2:30 没有发生! 为了避免这种每年一小时的情况出现错误,大多数计算环境(包括 ECMAScript)将使用转换之前的偏移量或转换之后的偏移量将跳过的时钟时间转换为准确时间。

2025 年,是时候彻底搞懂 JavaScript Date 了!

在这两种情况下,解决将本地时间转换为准确时间时的歧义 需要选择使用两个可能的偏移量中的哪一个或者抛出异常。

在 Temporal 中,如果 确切的时间或时区偏移已知,则不可能存在歧义。例如:

// 不可能有歧义,由于源是 UTC 中的准确时间
inst = Temporal.Instant.from('2020-09-06T17:35:24.485Z');
// => 2020-09-06T17:35:24.485Z
// 偏移量可以使本地时间 “准确” 而不会出现歧义
inst = Temporal.Instant.from('2020-09-06T10:35:24.485-07:00');
// => 2020-09-06T17:35:24.485Z
zdt = Temporal.ZonedDateTime.from('2020-09-06T10:35:24.485-07:00[America/Los_Angeles]');
// => 2020-09-06T10:35:24.485-07:00[America/Los_Angeles]
// 如果源是准确的 Temporal 对象,则不可能出现歧义。
zdt = inst.toZonedDateTimeISO('America/Los_Angeles');
// => 2020-09-06T10:35:24.485-07:00[America/Los_Angeles]
inst2 = zdt.toInstant();
// => 2020-09-06T17:35:24.485Z

但是,从非准确源创建准确时间类型(Temporal.ZonedDateTime 或 Temporal.Instant)时,可能会出现歧义,列如下面的例子:

// 偏移量未知,可能歧义
zdt = Temporal.PlainDate.from('2019-02-19').toZonedDateTime('America/Sao_Paulo');
// can be ambiguous
zdt = Temporal.PlainDateTime.from('2019-02-19T00:00').toZonedDateTime('America/Sao_Paulo');
// can be ambiguous
// 即使源字符串中存在偏移量,如果类型(如 PlainDateTime)
// 不是准确类型,则解析时会忽略偏移量,因此可能会出现歧义。
dt = Temporal.PlainDateTime.from('2019-02-19T00:00-03:00');
zdt = dt.toZonedDateTime('America/Sao_Paulo');
// can be ambiguous
// 从准确类型转换为非准确类型时,偏移量会丢失
zdt = Temporal.ZonedDateTime.from('2020-11-01T01:30-08:00[America/Los_Angeles]');
  // => 2020-11-01T01:30:00-08:00[America/Los_Angeles]
dt = zdt.toPlainDateTime();
// offset is lost!
// => 2020-11-01T01:30:00
zdtAmbiguous = dt.toZonedDateTime('America/Los_Angeles');
// can be ambiguous
// => 2020-11-01T01:30:00-07:00[America/Los_Angeles]
// 请注意,目前的偏移量为 -07:00(太平洋夏令时间),即 “第一个” 凌晨 1:30
// 不是像原始时间那样的 -08:00(太平洋标准时间),即 “第二个” 上午 1:30

为了解决这种可能的歧义,从不准确的源创建准确类型的时间方法 接受 disambiguation 选项,该选项控制在歧义的情况下返回的确切时间:

  • compatible:对于向后转换,其作用类似于 “earlier”;对于向前转换,作用类似于 “later”。
  • earlier:将返回两个可能的确切时间中 较早 的一个
  • later:将返回两个可能的确切时间中 较晚 的一个
  • reject:抛出 RangeError

与现有代码或服务互操作时,“兼容” 模式与旧版 Date 以及 moment.js、Luxon 和 date-fns 等库的行为相匹配。 此模式还符合 RFC 5545 (iCalendar) 等跨平台标准的行为。

4.2 DST 夏令时修改 Offset 导致时间二义性

进入夏令时时,时钟向前拨动一个小时, 移动的不是时间而是偏移量,偏移量向前移动会产生一个小时已经消失的错觉。 如果观察计算机的数字时钟, 可以看到它从 1:58 移动到 1:59 到 3:00。

当添加偏移量时,可以更轻松地了解实际发生的情况,结果是 1:59:59 到 3:00:00 之间的任何时间都从未真正发生过。

// 春季 DST 开始后跳过的时钟小时内时间的不同消歧模式
// 偏移量 -07:00 是夏令时,而偏移量 -08:00 表明标准时间
props = {timeZone: 'America/Los_Angeles', year: 2020, month: 3, day: 8, hour: 2, minute: 30};
zdt = Temporal.ZonedDateTime.from(props, { disambiguation: 'compatible'});
// 输出值 => 2020-03-08T03:30:00-07:00[America/Los_Angeles]
zdt = Temporal.ZonedDateTime.from(props);
// 输出值 => 2020-03-08T03:30:00-07:00[America/Los_Angeles]
// ('compatible' is the default)
earlier = Temporal.ZonedDateTime.from(props, { disambiguation: 'earlier'});
// 输出值 => 2020-03-08T01:30:00-08:00[America/Los_Angeles]
// (1:30 clock time; 依然在标准时间)
later = Temporal.ZonedDateTime.from(props, { disambiguation: 'later'});
// 输出值 => 2020-03-08T03:30:00-07:00[America/Los_Angeles]
// 'later' 和'compatible' 在后向转化时一致
later.toPlainDateTime().since(earlier.toPlainDateTime());
// 输出值  => PT2H
// (2 hour difference in clock time...
later.since(earlier);
// 输出值 => PT1H
// ... but 1 hour later in real-world time)

同样,在夏令时结束时,时钟向后拨动一小时。 在这种情况下,错觉就是一个小时重演。 在 “earlier” 模式下,确切时间将是复制的挂钟时间的较早实例。 在 “later” 模式下,确切时间将是重复时间的较晚实例。 在 “兼容” 模式下,返回的时间与 “较早” 模式一样,这与使用旧版日期的现有 JavaScript 代码的行为相匹配。

// 秋季 DST 结束后重复时钟小时内时间的不同消歧模式
// 偏移量 -07:00 是夏令时,而偏移量 -08:00 表明标准时间。
props = {timeZone: 'America/Los_Angeles', year: 2020, month: 11, day: 1, hour: 1, minute: 30};
zdt = Temporal.ZonedDateTime.from(props, { disambiguation: 'compatible'});
// 输出值 => 2020-11-01T01:30:00-07:00[America/Los_Angeles]
zdt = Temporal.ZonedDateTime.from(props);
// 输出值 => 2020-11-01T01:30:00-07:00[America/Los_Angeles]
// 'compatible' is the default.
earlier = Temporal.ZonedDateTime.from(props, { disambiguation: 'earlier'});
// => 2020-11-01T01:30:00-07:00[America/Los_Angeles]
// 'earlier' is same as 'compatible' for backwards transitions.
later = Temporal.ZonedDateTime.from(props, { disambiguation: 'later'});
// => 2020-11-01T01:30:00-08:00[America/Los_Angeles]
// 同样的时间,但是延迟了 1h,-08:00 表明标准时间
// -08:00 offset indicates Standard Time.
later.toPlainDateTime().since(earlier.toPlainDateTime());
// => PT0S
// (same clock time...
later.since(earlier);
// => PT1H
// ... but 1 hour later in real-world time)

4.3 时区永久更改导致的日期二义性

时区定义可能会更改,这些变化几乎总是向前的,因此不会影响历史数据。 但计算机有时会存储有关未来的数据! 例如,日历应用程序可能会记录用户想要提醒明年朋友的生日。

zdt = Temporal.ZonedDateTime.from(savedUsingOldTzDefinition, { offset: 'reject'});
// 具体看下面的示例部分

当未来时间的日期时间数据与偏移量 (offset) 和时区 (timeZone) 一起存储时,如果时区定义发生更改,则新的时区定义可能会与先前存储的数据发生冲突。 在这种情况下则可以使用
Temporal.ZonedDateTime.from 的偏移选项来解决冲突 。

  • use:如果输入中含有时区偏移量则使用,即使当地时间与最初存储的时间不同,从而保持准确时间 UTC 不变。
  • ignore: 永不使用输入中提供的时区偏移量,而是计算与时区的偏移量,从而保证当地时间不变,但可能会导致与最初存储的准确时间不同。
  • prefer:使用偏移量对此时区有效则使用, 如果偏移量无效,则计算与时区的偏移量。
  • reject:如果偏移量对于所提供的时区中提供的日期和时间无效,则抛出 RangeError。


Temporal.ZonedDateTime.from 的默认值是 reject,由于没有明显的默认解决方案。 相反,开发人员需要决定如何修复目前无效的数据。

请注意,偏移与时区冲突仅对 Temporal.ZonedDateTime 重大,由于没有其他时间类型接受 IANA 时区和时区偏移作为任何方法的输入。 例如,Temporal.Instant.from 永远不会遇到冲突,由于 Temporal.Instant 类型会忽略输入中的时区并仅使用偏移量 。

5. 时区 Offset 偏移选项示例

偏移量 offset 可用于 解析在更改该时区的时区定义之前保存的值。 例如,巴西于 2019 年停止遵守夏令时,并于 2019 年 2 月 16 日最终结束夏令时,永久停止夏令时的更改于 2019 年 4 月宣布。

想象一个在 2018 年运行的应用程序以字符串格式保存了一个未来时间,其中包含 偏移量和 IANA 时区。
Temporal.ZonedDateTime.prototype.toString 以及使用与 Java.time.ZonedDateTime 等一样格式的其他平台和库都使用这种格式。 假设存储的未来时间是圣保罗 2020 年 1 月 15 日中午:

zdt = Temporal.ZonedDateTime.from({year: 2020, month: 1, day: 15, hour: 12, timeZone: 'America/Sao_Paulo'});
zdt.toString();
// => 2020-01-15T12:00:00-02:00[America/Sao_Paulo]
// 假设该字符串保存在外部数据库中,偏移量 “-02:00” 为夏令时

// 请注意,如果今天运行上面的代码将返回一个偏移量 `-03:00`
// 由于其反映了之后的当前时区定义,而夏令时被废除。
// 但在 2018 年运行会返回 `-02:00`,即对应于巴西当时的夏令时

该字符串在 2018 年创建并保存时有效,但在 2019 年 4 月更改时区规则后,2020-01-15T12:00-02:00[America/Sao_Paulo] 不再有效,由于正确的偏移量目前为 -03:00。 当使用当前时区规则解析此字符串时,Temporal 需要通过 offset 知道如何处理。

savedUsingOldTzDefinition = '2020-01-01T12:00-02:00[America/Sao_Paulo]';
// 以前存储的字符串
/* WRONG */ zdt = Temporal.ZonedDateTime.from(savedUsingOldTzDefinition);
// 报错 => RangeError: Offset is invalid for '2020-01-01T12:00' in 'America/Sao_Paulo'. Provided: -02:00, expected: -03:00.
// 默认是当 offset 和 timezone 冲突时抛出异常
/* WRONG */ zdt = Temporal.ZonedDateTime.from(savedUsingOldTzDefinition, { offset: 'reject'});
// 报错 => RangeError: Offset 无效 '2020-01-01T12:00' in 'America/Sao_Paulo'. Provided: -02:00, expected: -03:00.
zdt = Temporal.ZonedDateTime.from(savedUsingOldTzDefinition, { offset: 'use'});
// => 2020-01-01T11:00:00-03:00[America/Sao_Paulo]
// 使用旧的 offset 解析 date/time
// 保证时钟时间为 11:00 下,但是 UTC 时间一致
zdt = Temporal.ZonedDateTime.from(savedUsingOldTzDefinition, { offset: 'ignore'});
// => 2020-01-01T12:00:00-03:00[America/Sao_Paulo]
// 使用当前 timezone 计算 offset,忽略保存的 offset
zdt = Temporal.ZonedDateTime.from(savedUsingOldTzDefinition, { offset: 'prefer'});
// => 2020-01-01T12:00:00-03:00[America/Sao_Paulo]
// 保存的 offset 在当前 timezone 规则下无效
// 因此使用保存的 timezone 重新计算 offset 偏移

6. 关于 Temporal 的几个疑问

6.1 UTC 偏移量和时区之间的差异

UTC 偏移量(Offset)和时区 (TimeZone) 是相关的概念,但有不同的用途。

2025 年,是时候彻底搞懂 JavaScript Date 了!

可以将时区定义为使用一样标准时间(注意是标准时间)的区域,而 UTC 偏移量是 定义和表达每个时区内当地时间的一种方法。

6.2 夏令时 TimeZone 可以随时调整

UTC 全年保持不变,不受夏令时影响。但是,一些国家 / 地区在夏令时期间会切换到不同的时区。

例如,纽约在夏令时期间会转到东部夏令时,即 UTC-4。当时钟在秋季调回标准时间一小时时,纽约将恢复东部标准时间和 UTC-5。

2025 年,是时候彻底搞懂 JavaScript Date 了!

虽然大多数时区与 UTC 相差整个小时,但也有少数时区存在 30 分钟和 45 分钟的偏移。 这就是为什么,尽管 UTC 基于 24 小时模型并且始终以 24 小时格式书写,但 UTC 偏移量的枚举却可能超过 24 个。

参考资料

https://tc39.es/proposal-temporal/docs/ambiguity.html

https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

https://stackoverflow.com/questions/522251/whats-the-difference-between-iso-8601-and-rfc-3339-date-formats

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt

https://www.unixtutorial.org/unix-epoch/

https://simplyscheduleappointments.com/guides/timezones-and-offsets/

https://www.zhihu.com/question/20309772/answer/2691755794

https://stackoverflow.com/questions/8053648/determine-dates-of-dst-switch-both-forwards-and-backwards-for-a-timezone-in-ja

https://www.timeanddate.com/time/utc-offsets.html

https://www.timeanddate.com/time/current-number-time-zones.html

© 版权声明

相关文章

5 条评论

  • 头像
    一帆 读者

    “为了避免这种每年一小时的情况出现错误,大多数计算环境(包括 ECMAScript)将使用转换之前的偏移量或转换之后的偏移量将跳过的时钟时间转换为精确时间。” 这句话的核心逻辑是:当遇到“跳过”的时间(例如由于夏令时开始跳过的02:30),系统不会让它报错或悬在那里,而是会强行把它“掰弯”,映射到一个真实存在的 UTC 时间点上。 这时候有两种策略:📉 策略 A:使用“转换之前的偏移量” (Before Offset);📈 策略 B:使用“转换之后的偏移量” (After Offset)

    无记录
    回复
  • 头像
    被饭盒追打的狗 投稿者

    “UTC 转本地不可能存在二义性”,这在数学计算上是绝对正确的。● UTC 06:00 -> 转换为本地时间,结果永远是那个第一次出现的 01:00 。● UTC 07:00 -> 转换为本地时间,结果永远是那个第二次出现的 01:00 。 但是,如果我们从人类感知或日志记录的角度来看,这种转换会产生一种“反直觉”的现象:
你把两个不同的 UTC 时间点(06:00 和 07:00)转换成本地时间后,得到的挂钟读数看起来完全一样(都是 01:00)。如果不额外标注是“夏令时”还是“标准时”(或者不记录 UTC 偏移量),这两个时间在本地就“撞车”了。

    无记录
    回复
  • 头像
    开心洋芋蛋- 读者

    “在 Temporal 中,如果 确切的时间或时区偏移已知,则不可能存在歧义”这是因为utc转化为本地时间时候自动考虑了时区偏移和夏令时等因素了

    无记录
    回复
  • 头像
    呼和浩特校园 投稿者

    收藏了,感谢分享

    无记录
    回复