将DateTime从特定时区转换为UTC - 缺少小时?

时间:2013-08-06 11:20:56

标签: c# datetime timezone

我无法理解如何正确地将DateTime转换为不同的时区。

让我们说,我希望将DateTime与时间:美国东部时间的10:00(军事)转换为UTC中的DateTime

以下是我的尝试:

DateTime unspecified = new DateTime(2013, 8, 15, 10, 0, 0, DateTimeKind.Unspecified);
var utc = TimeZoneInfo.ConvertTime(unspecified, TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"), TimeZoneInfo.Utc);

...我用DateTime构建DateTimeKind.Unspecified,因为它既不是UTC,也不是本地时间(美国东部时间10点)。然后我将其传递给TimeZoneInfo.ConvertTime,告诉它在EST中是DateTime,我想将其转换为UTC。

由于EST is 5 hours behind of Coordinated Universal Time (UTC)我希望utc等于{15.08.2013 15:00:00},但是当我运行上面的代码时,由于某种原因,得到{15.08.2013 14:00:00}(即时差为 4小时)。

问题是:为什么?这是某种白天节约时间吗?如果是这样 - 如何在没有白天节省时间的情况下进行此转换?

3 个答案:

答案 0 :(得分:1)

Id "Eastern Standard Time"的Windows时区不仅适用于EST。它涵盖EST(-5)和EDT(-4)。你不会仅仅从id名称知道它。这有点命名异常是Microsoft Windows时区数据库的几个棘手问题之一。有关详细信息,请参阅the timezone tag wiki

幸运的是,它不是唯一的数据库。它甚至不是最常用的数据库,它只是Windows和.Net附带的默认数据库。要使用标准IANA时区数据库执行此转换,请使用Noda Time

DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
LocalDateTime dt = new LocalDateTime(2013, 8, 15, 10, 0, 0);
ZonedDateTime zdt = tz.AtLeniently(dt);
Instant utc = zdt.ToInstant();

另请注意Noda Time如何为您提供无法解释的类型。没有Kind影响行为。 “Local”在这里只是意味着一些本地值,而不是你自己的本地时钟。

另请注意,我使用AtLeniently将日期应用于时区。这是一种在应用模糊或无效时间时进行调整的策略。还有AtStrictly,它会在这些场景中抛出异常。或者,您可以创建自己的策略。 TimeZoneInfo类没有这种控制级别。

答案 1 :(得分:0)

是的,应用了dalylight保存。见Wikipedia

  

在观察标准时使用东部标准时间(EST)的地方   时间(秋/冬)<协调世界时>后<强> 5小时   (UTC-05:00)。

     

东部夏令时(EDT),观察夏令时   (春/夏)在协调世界时的后面<强> 4小时   (UTC-04:00)。

转换方法是正确的。你对EST时区的假设是有缺陷的。如果您的输入日期确实是EST,那么转换是正确的。如果这不符合您的期望,您需要检查输入数据的来源以及输入的时区。 如果您正在处理数据库中保存的日期,并且您不知道什么是正确的,哪些不是您遇到麻烦。

一般来说,使用DateTimeOffset而不是DateTime更安全,因为它确实将UTC时间作为DateTime存储,并将本地时区偏移作为其中的附加值存储。这使得从当地时间确定真实的UTC时间变得微不足道。

答案 2 :(得分:0)

您可以轻松地将任何时区的任何DateTime转换为UTCDateTime。

Here is the Example

   string DisplayName = "custom standard name here";
   string StandardName = "custom standard name here"; 
   string YourDate="2013/8/15 10:0:0"; 
   TimeSpan Offset = new TimeSpan(+10, 00, 00);
   TimeZoneInfo TimeZone = TimeZoneInfo.CreateCustomTimeZone(StandardName, Offset, DisplayName, StandardName);
   var RawDateTime = DateTime.SpecifyKind(DateTime.Parse(YourDate), DateTimeKind.Unspecified);
   DateTime UTCDateTime = TimeZoneInfo.ConvertTimeToUtc(RawDateTime, TimeZone);
   Console.WriteLine(UTCDateTime);