最稳妥获取毫秒时间戳的方式是 DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),它返回自1970-01-01T00:00:00Z起的毫秒数,与JS、Python等对齐,避免时区偏差和精度陷阱。

用 DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() 拿毫秒时间戳最稳妥
它返回的是从 1970-01-01T00:00:00Z 到现在的毫秒数,和 JavaScript 的 Date.now()、Python 的 time.time() * 1000 对齐,跨系统传时间戳不会错。
别用 DateTime.Now.Ticks / 10000 手动算——容易漏掉时区偏移,本地时间转 Unix 时间戳会偏移 8 小时(东八区);也别依赖 DateTime.Now.Millisecond,它只返回当前秒内的毫秒(0–999),不是完整时间戳。
-
DateTimeOffset.UtcNow自带 UTC 时区信息,不依赖本地系统时区设置 - 如果必须用
DateTime,至少写DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds,但更啰嗦且易出错 - 注意返回值是
long,不是int,2038 年后也能用
高精度场景别碰 DateTime,改用 Stopwatch
如果你要测代码执行耗时、做微秒级计时或需要单调递增(不受系统时间调整影响),DateTime 系列完全不合适。它的分辨率通常只有 10–15ms,而且系统时间被手动/自动校准(比如 NTP 同步)时可能倒退或跳变。
-
Stopwatch.GetTimestamp()返回 CPU 计数器原始值,配合Stopwatch.Frequency可换算成纳秒级时间差 -
Stopwatch.ElapsedMilliseconds是常用简写,但本质仍是基于计数器,不随系统时间变化 - 不要把
Stopwatch的值当成“绝对时间”,它只适合相对计时(如耗时统计)
DateTime.Now 和 DateTime.UtcNow 的性能与线程安全差异很小,但语义不能混
两者底层都调用 Windows API GetSystemTimeAsFileTime,性能几乎无差别;.NET Core 2.1+ 之后还做了缓存优化,每 10–15ms 才真正查一次系统时钟。
- 在 Web API 或日志打点中,一律用
DateTime.UtcNow:避免日志时间因服务器时区不同而混乱 -
DateTime.Now只在跟用户交互的界面层(如显示“今天下午 3:20”)才合理 - 多线程下它们都是只读结构体,不存在线程安全问题,但别拿
DateTime.Now去算服务端超时逻辑——时区一变就失效
注意 .NET Framework 和 .NET Core 的默认精度差异
Windows 上,DateTime 的底层精度受限于系统时钟粒度,默认约 15.6ms(由 GetSystemTimeAdjustment 决定),不是你想象中的“毫秒级”。虽然 ToUnixTimeMilliseconds() 能输出毫秒数字,但连续两次调用可能返回相同值。
- .NET 6+ 在 Windows 上可通过
AppContext.SetSwitch("System.Runtime.InteropServices.ThrowOnCantFindDll", true)启用高精度 API(需 Windows 10 1803+),但多数业务不需要 - 真要亚毫秒精度,只能上
Stopwatch或 P/InvokeQueryPerformanceCounter - 别在单元测试里断言
DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()每次都变——它很可能不变
事情说清了就结束。时间戳看着简单,但时区、精度、用途三者一搅和,错一点就埋坑。










