用datetimeoffset.fromunixtimeseconds最稳:它安全、时区明确,默认按utc解析;毫秒级需先/1000转秒级(用long防溢出),.net 6+可用fromunixtimemilliseconds简化。

Unix时间戳转DateTime:用DateTimeOffset.FromUnixTimeSeconds最稳
Unix时间戳(秒级)直接转DateTime不能硬除1000再加纪元——C#里没内置“秒级转DateTime”的静态方法,但DateTimeOffset提供了安全、时区明确的入口。它默认按UTC解析,后续再转本地或指定时区更可控。
常见错误是手写new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp),看似可行,但容易忽略DateTimeKind传播问题,尤其在序列化或跨时区传递时出错。
-
DateTimeOffset.FromUnixTimeSeconds(timestamp)返回带UTC偏移的值,可直接调.DateTime或.UtcDateTime - 若输入是毫秒级(如JavaScript
Date.now()),先整除1000:timestampMs / 1000,注意用long避免溢出 - 传入负数(1970年前)也支持,但
DateTime最小值是0001-01-01,超范围会抛ArgumentOutOfRangeException
毫秒级时间戳别漏掉/1000,但要注意整除截断
很多API返回的是毫秒级时间戳(13位数字),比如1717023600000。直接喂给FromUnixTimeSeconds会当成“一千七百一十七万亿秒”,远超纪元后几百年,结果是公元5万年+的日期——程序不报错,但逻辑全歪。
正确做法是先转成long再整除1000,不是强制转换或(int)ts/1000(32位溢出风险高):
long tsMs = 1717023600000L; DateTime dt = DateTimeOffset.FromUnixTimeSeconds(tsMs / 1000).DateTime;
- 用
L后缀确保字面量是long,避免编译期隐式转int失败 - 不要用
Math.DivRem或Convert.ToInt64绕路,/1000足够清晰 - 如果原始值来自JSON反序列化(如
long?),记得判空再除
转完要不要.ToLocalTime()?看场景
从Unix时间戳还原的时间本质是UTC时刻。是否调.ToLocalTime()取决于你后续怎么用它:
- 存数据库、发HTTP API、做时间计算——保持UTC(用
.UtcDateTime或.DateTime配合DateTimeKind.Utc) - 显示给用户看、写日志、生成报表——才需要转本地时区,此时用
.ToLocalTime() - 服务器部署在Docker或Linux容器里,
TimeZoneInfo.Local可能不是你预期的时区,建议显式指定:dt.ToLocalTime()只适合开发机调试
一个典型坑:把UTC时间直接当本地时间存进SQL Server的datetime字段,再查出来用.ToLocalTime()二次转换,结果多转了一次——时间就飘了8小时。
DateTimeOffset.FromUnixTimeMilliseconds是.NET 6+才有的甜点
.NET 6起新增了DateTimeOffset.FromUnixTimeMilliseconds,省去手动除1000的步骤,代码更直白:
DateTime dt = DateTimeOffset.FromUnixTimeMilliseconds(1717023600000L).DateTime;
但它只在.NET 6及以上可用,老项目(.NET Framework 4.8 / .NET Core 3.1)必须用FromUnixTimeSeconds + 手动换算。别在.csproj里升级TargetFramework后忘了测兼容性——有些NuGet包在低版本运行时仍会走旧路径。
另外,这个方法不接受null或小于-62135596800000(对应0001-01-01)的值,越界照样抛异常,不能假设它“更宽容”。
真正麻烦的从来不是转换函数本身,而是时间戳来源不清:前端传的?数据库存的?第三方API文档写的“timestamp”到底指秒还是毫秒?校验第一步永远该是打日志看原始值位数,而不是急着写转换逻辑。











