Skip to content

日期与时区 ​

选择模型前,先区分字段表示日历日期、本地钟表时间还是具体时间点。控件显示、DTO 值与请求时区头有不同职责。

选择表示方式 ​

业务值表示示例
出版日期只含日期的字符串2026-10-04
每日营业时间只含时间的字符串09:30
需要按指定时区解释的预约本地日期时间加明确时区2026-10-04T09:30、Asia/Shanghai
已发生事件的时间点带偏移的时间戳2026-10-04T01:30:00Z

日期控件 使用 string/null,不把本地预约自动转成 UTC。转换由 DTO 与业务规则决定。夏令时的歧义时间需要明确策略,控件不会自动选择。

格式化显示 ​

创建 src/utils/date-display.ts:

ts
export function formatInstant(iso: string, culture: string, timeZone: string): string {
  const date = new Date(iso);
  if (Number.isNaN(date.getTime())) return '—';
  return new Intl.DateTimeFormat(culture, {
    dateStyle: 'medium',
    timeStyle: 'short',
    timeZone,
  }).format(date);
}

export function formatCalendarDate(value: string, culture: string): string {
  // UTC is used only to format a date-only value without shifting the calendar day.
  const [year, month, day] = value.split('-').map(Number);
  if (!year || !month || !day) return '—';
  return new Intl.DateTimeFormat(culture, { dateStyle: 'medium', timeZone: 'UTC' }).format(
    new Date(Date.UTC(year, month - 1, day)),
  );
}

在 computed 或模板使用的函数中调用 formatInstant(record.createdAt, localization.currentLang.value, 'Asia/Shanghai'),输入应是带偏移的有效 ISO 时间戳。有效的日期 DTO 可调用 formatCalendarDate('2026-10-04', culture)。这里仅用 UTC 格式化以保留日历日,不是把生日转换成具体时间点。

不要把只含日期的字段按 UTC 解析后再用任意本地时区显示,否则可能显示前一天。本地日期时间也不能在尚未明确用户所指时区时直接用 toISOString() 保存。

框架请求头 ​

应用配置 clock.kind 为 Utc 时,时区拦截器添加 __timezone。优先使用 setting.values['Abp.Timing.TimeZone'],否则使用浏览器 Intl 解析的时区。已有请求头会保留,skipAddingHeader 会跳过该请求的框架头添加。

请求头提供后端请求上下文,不重写 JSON 日期,也不决定日期控件模型格式。租户或用户设置变化时检查有效配置,改变有效时区后刷新配置。

检查日期行为 ​

检查午夜附近日期、同一时间点在两个时区的显示、空可选字段及后端夏令时规则。无效数据应给出反馈,不能猜测时区后保存。参见HTTP、设置和本地化。

非官方社区项目,采用 MIT 许可证,与 Volosoft 无关。