对接一个第三方接口,文档要求传 10 位秒级时间戳,同事用 DateTime.Now 转出来,签名一直对不上。原因很简单:时间戳本身不带时区,拿本地时间再算,等于整体偏了 8 小时。

新版本一行就够

DateTimeOffset.UtcNow.ToUnixTimeSeconds() 得到秒级时间戳,ToUnixTimeMilliseconds() 得到毫秒级。.NET Core 和 .NET 5 以后都能直接用,.NET Framework 4.6 起也有这两个方法。用 UtcNow 而不是 Now,是因为本地时间在夏令时或者时区设置异常时会跳,UTC 不会。

老框架的写法

没有这两个方法时,用 DateTime.UtcNow 减去 1970 年 1 月 1 日零点,取 TotalSeconds 再转成 long。减法只按时间刻度算,不涉及时区换算,但被减数必须是 UtcNow,写成 Now 就错。毫秒用 TotalMilliseconds,别自己乘 1000 再拼字符串,容易溢成负数。

秒和毫秒别混

前端 Date.now() 给的是 13 位毫秒,后端很多接口要 10 位秒。传错位数,服务端会解析成一个几万年后的时间,签名校验直接失败,报错信息还看不出是这个问题。转换的地方在方法名上写清单位,别用一个 GetTimestamp 到处复用,后面接手的人只能靠猜。

反解和耗时要分开处理

从时间戳还原,用 DateTimeOffset.FromUnixTimeSeconds,再转成本地时间展示。数据库存时间优先存 UTC,展示层再转,跨时区部署时省掉一堆麻烦。测接口耗时不要用时间戳,用 Stopwatch,它读高精度计数器,不受系统时间校正影响,时间戳那点精度在毫秒级场景根本不够。

数据库字段别用 int 存秒级时间戳,2038 年就会溢出,用 long 或 bigint,改表结构比改代码省事。

判断标准:要跨机器、跨时区传,就用 UTC 秒级时间戳;只在页面显示,用带偏移的 DateTimeOffset。别拿本地时间做任何持久化。