UTC DateTime转指定时区DateTimeOffset的结果疑问及代码排查
问题分析与解决
你的预期是正确的
UTC时间2022-01-01 12:00:00转换为纽约时区(当时为东部标准时间,UTC-5),当地时间确实是2022-01-01 07:00:00,对应的DateTimeOffset应该是2022-01-01 07:00:00 -05:00。
代码中的错误
扩展方法核心问题
问题出在ToLocalDateTimeOffset方法的这一行:
var localDateTimeOffset = new DateTimeOffset(utcDateTime, timeZone.GetUtcOffset(utcDateTime));
你传入了原始UTC时间作为DateTimeOffset的日期时间部分,而非转换后的当地时间localDateTime。这导致最终结果的时间部分仍为UTC的12点,只是附加了纽约时区的偏移量,从而得到错误的2022-01-01 12:00:00 -05:00。
测试方法的问题
测试代码里的预期值计算逻辑有误:
var expectedDateTime = DateTimeExtensionTestHelpers.SomeUtcDateTime + utcOffset;
纽约时区的偏移量是-05:00,虽然数值计算后得到07:00,但expectedDateTime的Kind属性是Unspecified,而实际返回的是DateTimeOffset类型,直接用ShouldBe断言会存在类型匹配风险。另外测试中调用的方法名ToLocalDateTime与扩展方法名ToLocalDateTimeOffset不一致,会导致编译错误。
修正后的代码
修正扩展方法
public static DateTimeOffset ToLocalDateTimeOffset( this DateTime utcDateTime, string? locationTimeZone, string defaultTimezoneIfNoneProvided = CommonConstants.SYDNEY_TIMEZONE) { if (string.IsNullOrWhiteSpace(defaultTimezoneIfNoneProvided)) { throw new Exception("Default timezone must be provided."); } var timeZone = GetTimeZoneInfo(locationTimeZone, defaultTimezoneIfNoneProvided); // 将UTC时间转换为目标时区的当地时间 var localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, timeZone); // 使用转换后的当地时间和对应偏移量创建DateTimeOffset var localDateTimeOffset = new DateTimeOffset(localDateTime, timeZone.GetUtcOffset(localDateTime)); return localDateTimeOffset; }
关键修改:用转换后的localDateTime替代原始utcDateTime构造DateTimeOffset,确保时间部分为目标时区的当地时间。
修正测试方法
[Fact] public void ToLocalDateTime_GivenATimeZone_ShouldReturnALocalDateTimeForTheProvidedTimeZone() { // Arrange var expected = new DateTimeOffset(2022, 1, 1, 7, 0, 0, TimeSpan.FromHours(-5)); // Act var result = DateTimeExtensionTestHelpers.SomeUtcDateTime.ToLocalDateTimeOffset( DateTimeExtensionTestHelpers.NewYorkTimeZone, DateTimeExtensionTestHelpers.SydneyTimezone); // Assert result.ShouldBe(expected); }
直接构造正确的DateTimeOffset预期对象,避免偏移量计算带来的类型问题,同时修正方法名匹配问题。
内容的提问来源于stack exchange,提问作者Pure.Krome
相关产品推荐
相关产品推荐

