Web 功能:
Temporal
众所周知,使用旧版 Date 对象安排跨不同时区的活动非常困难,尤其是在夏令时 (DST) 转换期间,因为时间可能会被跳过或重复。
Temporal API 提供 Temporal.ZonedDateTime 来表示特定时区中的日期和时间,并以可预测的方式自动处理夏令时转换。
如何实现
如需协调全球活动并处理潜在的夏令时冲突,请执行以下操作:
- 强制性: 创建 ZonedDateTime:使用
Temporal.ZonedDateTime.from()创建可感知时区的日期时间对象。 - 强制性: 处理歧义:使用
disambiguation选项控制时间不明确或不存在(例如,在时钟更改期间)时的行为。 - 强制性: 转换时区:使用
.withTimeZone()查看其他地点的等效时间。
示例:安排和冲突检测
// 1. Define the event time and target time zone
const date = "2025-03-09";
const time = "02:30"; // This time is skipped in New York during Spring Forward
const timeZone = "America/New_York";
const inputStr = `${date}T${time}[${timeZone}]`;
// 2. Detect conflicts using 'reject'
let hasConflict = false;
try {
// 'reject' throws RangeError if the time is ambiguous or does not exist
Temporal.ZonedDateTime.from(inputStr, { disambiguation: 'reject' });
} catch (e) {
if (e instanceof RangeError) {
hasConflict = true;
console.log("This time falls in a DST transition gap or overlap.");
}
}
// 3. Resolve the time safely using 'compatible' (default)
// 'compatible' will resolve to a valid time even if skipped or repeated
const hostTime = Temporal.ZonedDateTime.from(inputStr, { disambiguation: 'compatible' });
console.log(`Resolved time: ${hostTime.toString()}`);
// 4. Convert to another time zone (e.g., Tokyo)
const tokyoTime = hostTime.withTimeZone("Asia/Tokyo");
// Use toLocaleString() for user-facing display instead of manual hour/minute padding
console.log(`Tokyo time: ${tokyoTime.toLocaleString('en-US', { hour: 'numeric', minute: '2-digit' })}`);
策略性实施和最佳实践
- 对于与特定地理位置绑定的活动(例如在特定城市举行的会议),请使用
Temporal.ZonedDateTime。 - 务必使用
disambiguation: 'reject',以便在夏令时转换期间检测日程冲突并向用户发出警告。 - 务必在您希望系统在发生冲突时自动选择合理时间时使用
disambiguation: 'compatible'(默认值)。 - 请勿将
Temporal.PlainDateTime用于全球活动,因为它不包含时区信息,无法反映夏令时变化。 - 要使用
.withTimeZone()计算其他位置的等效时间,而不改变原始对象(Temporal 对象不可变)。 - 务必使用原生
.toLocaleString()格式(例如{ hour: 'numeric', minute: '2-digit' })来显示面向用户的时间,而不是手动计算时间和填充。
后备策略
Temporal 的回退和浏览器支持
对于尚不支持原生 Temporal API 的浏览器,请使用功能检测并动态加载 temporal-polyfill(约 15 KB min+gz)。
请注意,导入 temporal-polyfill 不会自动将 Temporal 对象分配给全局范围。如果您的代码依赖于 globalThis.Temporal,请明确分配它。
// Check if Temporal is supported natively
(async () => {
if (typeof Temporal === 'undefined') {
// Load the polyfill conditionally
const module = await import('https://esm.sh/temporal-polyfill');
globalThis.Temporal = module.Temporal;
// Extend Date.prototype if needed
Date.prototype.toTemporalInstant = module.toTemporalInstant;
}
initializeApp();
})();