我有将长整数转换为日期的代码。

 DateTimeOffset value =
   DateTimeOffset.FromUnixTimeSeconds(1597325462);
   DateTime showTime = value.DateTime;
   string easternZoneId = "America/New_York";
   TimeZoneInfo easternZone =
       TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
   DateTime targetTime =
       TimeZoneInfo.ConvertTime(showTime, easternZone);
   Console.WriteLine("DateTime is {0}", targetTime);
在我的Mac上,输出为"DateTime is 8/13/2020 6:31:02 AM"在我的服务器上,输出为"DateTime is 8/13/2020 9:31:02 AM"两者上的代码相同。
Linux盒值是准确的。如何在Mac上获得相同的结果?

最佳答案

您正在使用的TimeZone.ConvertTime的重载采用DateTime值和目标TimeZoneInfo。由于没有提及源时区,因此可以从传入的.KindDateTime属性中推断出来。
在您的情况下,即DateTimeKind.Unspecified,因为.DateTimeDateTimeOffset属性始终返回unspecified,而不管偏移量是多少。
ConvertTime调用中,如果类型为DateTimeKind.Unspecified,则假定它是本地时间(就好像是DateTimeKind.Local一样)。 (向下滚动到“备注”部分in the docs here。)因此,您进行的转换就好像Unix时间戳是基于本地时间的,而不是实际上是基于UTC的。在工作站和服务器之间获得不同的结果是因为它们具有不同的系统本地时区,而不是因为它们运行的​​是不同的操作系统。
有很多不同的方法可以重写此代码以解决该问题。我将按照您的偏好为您提供一些选择:

  • 您可以在整个转换过程中将所有内容保留为DateTimeOffset:
    DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
    string easternZoneId = "America/New_York";
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    DateTimeOffset targetTime = TimeZoneInfo.ConvertTime(value, easternZone);
    
  • 您可以使用.UtcDateTime属性代替.DateTime属性:
    DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
    DateTime showTime = value.UtcDateTime;
    string easternZoneId = "America/New_York";
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    DateTime targetTime = TimeZoneInfo.ConvertTime(showTime, easternZone);
    
  • 您可以使用ConvertTimeFromUtc代替ConvertTime:
    DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
    DateTime showTime = value.DateTime;
    string easternZoneId = "America/New_York";
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    DateTime targetTime = TimeZoneInfo.ConvertTimeFromUtc(showTime, easternZone);
    
  • 您可以在ConvertTime调用中将UTC指定为源时区:
    DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
    DateTime showTime = value.DateTime;
    string easternZoneId = "America/New_York";
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    DateTime targetTime = TimeZoneInfo.ConvertTime(showTime, TimeZoneInfo.Utc, easternZone);
    

  • 还有其他一些选择,例如显式设置种类,但我认为以上内容为您提供了足够的机会。
    如有疑问,请选择第一个选项。在大多数情况下,DateTimeOffsetDateTime更容易合理化。

    07-24 16:05