我在理解如何将DateTime
正确转换为不同时区时遇到问题。
比方说,我想将时间为美国东部时间10:00(军用)的DateTime
转换为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);
我用DateTimeKind.Unspecified
构造DateTime
,因为它既不是UTC,也不是当地时间(现在是美国东部时间10:00)。然后我把它传给TimeZoneInfo.ConvertTime,告诉它这是EST中的DateTime
,我想把它转换成UTC。
由于EST比协调世界时(UTC)晚了5小时,我希望 问题是:为什么?这是为了节省白天的时间吗?如果是这样的话,如何在没有白天节省时间的情况下进行转换?utc
等于{15.08.2013 15:00:00}
,但当我运行高于I的代码时,由于某种原因,会得到{15.08.2013 14:00:00}
(即时差4小时
具有"Eastern Standard Time"
的Id
的Windows时区不仅仅用于EST。它包括EST(-5)和EDT(-4)。单从身份证的名字你是不会知道的。这有点命名异常,这是微软Windows时区数据库的几个奇怪之处之一。有关详细信息,请参阅时区标记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
。这里的"本地"只是指一些本地值,而不是您自己的本地时钟。
还要注意,我使用AtLeniently
将日期应用于时区。这是一种在应用模糊或无效时间时进行调整的策略。还有AtStrictly
,它将在这些场景中抛出异常。或者,你可以制定自己的策略。TimeZoneInfo
类没有这种级别的控制。
是的,应用了dalylight保存。参见维基百科
遵守标准时使用东部标准时间(EST)的地方时间(秋季/冬季)比协调世界时晚5小时(UTC−05:00)。
东部夏令时(EDT),当观测夏令时时(春季/夏季)比协调世界时晚4小时(UTC−04:00)。
转换方法正确。你对美国东部时间的假设是有缺陷的。如果您输入的日期确实是EST,那么转换是正确的。如果这不符合您的期望,您需要检查输入数据的来源以及实际输入的时区。如果你正在处理数据库中保存的日期,而你再也不知道什么是正确的,什么不是,你就有麻烦了。
一般来说,使用DateTimeOffset而不是DateTime更安全,因为它总是将UTC时间存储为DateTime,并将本地时区偏移量存储为其内部的附加值。这使得从本地时间确定真正的UTC时间变得微不足道。
您可以轻松地将任何时区的任何DateTime转换为UTCDateTime。
以下是示例
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);