agilelabs-fx-docs main topics/utility/timezone-utils.md

时区与时间工具

本页整理框架里和时间戳、UTC、本地时间、多时区上下文相关的可复用工具方法。内容基于当前工作区内的 agilelabsagilelabs.aspnet 实现扫描整理。

适用场景

  • API 入参与出参中的 Unix timestamp。
  • 数据库存储时间和业务展示时间的转换。
  • WorkContext 中的用户时区继承与读取。
  • AutoMapper 中的 DateTimeDateTimeOffset、时间戳互转。

核心源码入口

  • agilelabs/AgileLabs/DateTimeExtension.cs
  • agilelabs/AgileLabs/Json/Converters/DateTimeToTimestampJsonConverter.cs
  • agilelabs/AgileLabs/Json/Converters/NullableDateTimeToTimestampJsonConverter.cs
  • agilelabs.aspnet/src/AgileLabs.WebApp/WorkContexts/DefaultWorkContextCore.cs
  • agilelabs.aspnet/src/AgileLabs.EfCore.PostgreSQL/DateTime2DateTimeOffset.cs
  • agilelabs.aspnet/src/AgileLabs.EfCore.PostgreSQL/DatetimeMapping.cs
  • agilelabs.aspnet/src/AgileLabs.WebApp/AutoMappers/DateTimeOffsetToTimestampTypeConverter.cs

DateTimeExtension 提供的工具

agilelabs/AgileLabs/DateTimeExtension.cs 当前提供了 5 个常用入口:

  • GetEpochSeconds():把 DateTime 转成秒级 Unix 时间戳。
  • GetEpochMilliseconds():把 DateTime 转成毫秒级 Unix 时间戳。
  • FromEpochSeconds():把秒级 Unix 时间戳转回 DateTime,返回 UTC 基准时间。
  • FromEpochMilliseconds():把毫秒级 Unix 时间戳转回 DateTime,返回 UTC 基准时间。
  • ToChinaStandardTime():当输入是 Utc 时直接加 8 小时,否则原样返回。

最小示例:

var now = DateTime.UtcNow;
var ts = now.GetEpochMilliseconds();
var restored = ts.FromEpochMilliseconds();
var chinaTime = restored.ToChinaStandardTime();

JSON 层的时间工具

时间相关 JSON converter 位于 agilelabs/AgileLabs/Json/Converters/

  • DateTimeToTimestampJsonConverter
    • 写出时统一使用秒级时间戳。
    • 读取时同时兼容 10 位秒级、13 位毫秒级时间戳,以及可解析的时间字符串。
    • 时间戳读回后会执行 ToLocalTime()
  • NullableDateTimeToTimestampJsonConverter
    • 处理 DateTime?
    • 写出时仍是秒级时间戳。
    • 读取时只直接处理秒级时间戳或可解析字符串。

典型用法:

var settings = new JsonSerializerSettings();
settings.Converters.Add(DateTimeToTimestampJsonConverter.Instance);
settings.Converters.Add(NullableDateTimeToTimestampJsonConverter.Instance);

WorkContext 中的时区能力

agilelabs.aspnet 侧的时区上下文主要在 WorkContext:

  • DefaultWorkContextCore.TimeZoneInfo:根据 WorkContextTimeZoneInfo.TimeZoneId 解析当前上下文时区。
  • DefaultWorkContextCore.SetTimeZone(...):允许在当前上下文显式切换时区。
  • DefaultWorkContextCoreFactory:创建子上下文时可继承父级时区信息。

这意味着“用户展示时间”不应该只看服务器本地时区,而应优先看当前 WorkContext.TimeZoneInfo

AutoMapper 与存储层的时间转换

除了基础 DateTime 扩展方法,框架还在映射层提供了两组常见转换:

  • DateTimeOffsetToTimestampTypeConverter
    • 位于 agilelabs.aspnet/src/AgileLabs.WebApp/AutoMappers/DateTimeOffsetToTimestampTypeConverter.cs
    • 提供 DateTimeOffset <-> long 的秒级时间戳转换。
  • DateTime2DateTimeOffset
    • 位于 agilelabs.aspnet/src/AgileLabs.EfCore.PostgreSQL/DateTime2DateTimeOffset.cs
    • DateTime 按 UTC 语义转成 DateTimeOffset
    • DateTimeOffset 读回 DateTime 时转换为本地时间。

这组能力适合:

  • DTO 使用时间戳,领域或持久化层使用 DateTimeOffset
  • PostgreSQL 审计字段统一以 UTC 语义存储。

使用时要注意

  • DateTimeExtension 的时间戳转换依赖 TimeZoneInfo.ConvertTimeToUtc(date),调用前要确认 DateTime.Kind 语义清晰。
  • ToChinaStandardTime() 不是通用多时区方案,它只处理 UTC 到中国标准时间这一条路径。
  • DateTimeToTimestampJsonConverter 写出的是秒级,不是毫秒级;如果接口约定为毫秒级,需要项目级额外约束。
  • 显示给用户的时间优先结合 WorkContext.TimeZoneInfo,不要直接把服务器本地时间当用户时间。

相关页面