.NET中SystemClock.UtcNow.Millisecond为何始终返回0?
问题现象
服务中注入ISystemClock获取时间时,返回的DateTime实例Millisecond属性恒为0,直接实例化内置SystemClock取值结果一致,但直接调用DateTime.UtcNow、DateTimeOffset.UtcNow可获取到正常的毫秒数值。
对应业务实现代码:
public class EventSink { private readonly ISystemClock _systemClock; public EventSink(ISystemClock systemClock) { _systemClock = systemClock; } private async Task SaveEvent(CancellationToken ct) { var event = new MyEvent { Timestamp = _systemClock.UtcNow.DateTime }; } }
原服务注册代码:
services.AddScoped<ISystemClock, SystemClock>();
即时窗口测试输出:
DateTime.UtcNow.Millisecond 786 new SystemClock().UtcNow.Millisecond 0 System.DateTimeOffset.UtcNow.Millisecond; 265
原因
当前使用的SystemClock是ASP.NET Core早期鉴权组件内置的默认实现,类内部写死了时间截断逻辑:会将时间Ticks值对1秒对应的Ticks数取模,抹除所有不足1秒的时间片段,最终返回的时间精度仅到整秒,因此毫秒属性永远返回0,属于该旧实现的既定设计,不是运行时异常。
修复方式
根据项目实际情况二选一即可:
- 项目为ASP.NET Core 8及以上版本:直接废弃旧的
ISystemClock抽象,改用框架官方新增的TimeProvider时间抽象,默认TimeProvider.System实现返回的时间携带完整精度,单元测试时Mock逻辑也更简洁,直接注入使用即可。 - 项目需兼容旧代码必须保留
ISystemClock接口:不要使用内置的精度截断版SystemClock,自行实现高精度版本替换:
public class HighPrecisionSystemClock : ISystemClock { public DateTimeOffset UtcNow => DateTimeOffset.UtcNow; }
注册时替换原有实现:
services.AddScoped<ISystemClock, HighPrecisionSystemClock>();
替换后通过ISystemClock获取的时间就会携带正确的毫秒值。
内容的提问来源于stack exchange,提问作者Yoda
相关产品推荐
相关产品推荐

