为何Temporal.Now.zonedDateTimeISO()无法在Intl.DateTimeFormat中正常工作?
我正在开发一个Vue 3.x的i18n演示项目,目的是展示Intl.DateTimeFormat同时兼容传统的Date对象和新的Temporal API。目前Temporal.Now.plainDateISO()和Temporal.Now.plainTimeISO()都能正常和Intl.DateTimeFormat配合工作,但当我尝试把Temporal.Now.zonedDateTimeISO()的结果传给format方法时,就触发了运行时错误,可是单独调用Temporal.Now.zonedDateTimeISO()是能正常返回ZonedDateTime对象的。
问题原因
其实这个问题的核心在于:当前的Intl.DateTimeFormat.prototype.format方法并不直接支持Temporal.ZonedDateTime对象。它的参数只接受Date实例、能被解析为时间戳的数值(比如毫秒级时间戳),或者符合ISO格式的字符串。
而PlainDate和PlainTime能正常工作,是因为它们的设计更贴近传统日期时间的片段,Intl API对这类Temporal类型做了适配;但ZonedDateTime包含了时区、偏移量等更复杂的信息,目前还没被Intl的format方法直接兼容。
解决方案
有两种简单的方式可以解决这个问题,你可以根据自己的场景选择:
方案1:转换为毫秒级时间戳
把ZonedDateTime对象转换为毫秒级时间戳(通过epochMilliseconds属性),然后传给format方法,因为Intl可以直接处理数值类型的时间戳:
const temporalFormatter3 = computed(() => new Intl.DateTimeFormat(locale.value, { dateStyle: "long", timeStyle: "long"})); console.log(Temporal.Now.zonedDateTimeISO()); // 转换为毫秒时间戳后传入format const todayTemporalTimestamp = computed(() => temporalFormatter3.value.format(Temporal.Now.zonedDateTimeISO().epochMilliseconds));
方案2:直接使用ZonedDateTime的toLocaleString方法
Temporal对象本身就内置了toLocaleString方法,你可以直接传入locale和格式化配置,效果和使用Intl.DateTimeFormat完全一致,代码更简洁:
// 无需单独创建DateTimeFormat实例,直接调用toLocaleString const todayTemporalTimestamp = computed(() => Temporal.Now.zonedDateTimeISO().toLocaleString(locale.value, { dateStyle: "long", timeStyle: "long" }));
补充说明
Temporal是ECMAScript的新标准API,虽然现代浏览器(Chrome/Edge 90+、Firefox 109+)已经支持大部分特性,但Intl API对Temporal的全面兼容还在逐步完善中。未来随着规范更新和浏览器版本升级,Intl.DateTimeFormat应该会直接支持ZonedDateTime对象,但目前还是需要手动做一下转换。

