C#日期时间解析问题

16

尝试将日期/时间从字符串转换为DateTime时,我没有得到正确的值。

DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ",    CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

我的结果是2012-08-09 8:51:14 PM。为什么它会被偏移?我只想让它与输入的值相同。

5个回答

25

你正在解析 UTC 日期,但 DateTime.Kind 属性是本地时间。 你应该使用 DateTimeStyles.AdjustToUniversal 以将 Kind 属性标记为 Utc。

        DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

        Trace.WriteLine(testDate);  //  8/9/2012 8:51:14 PM
        Trace.WriteLine(testDate.ToString()); //  8/9/2012 8:51:14 PM
        Trace.WriteLine(testDate.ToUniversalTime()); //  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.Kind); // Local

       testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

        Trace.WriteLine(testDate);//  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.ToString());//  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.ToUniversalTime());//  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.Kind); // Utc

请注意:Steve说得一点也没错。注意,在更改为“AdjustToUniversal”后,默认情况下会打印为UTC……当要求为“ToUniversal”时也是如此。基本上,你所做的就是获取数据,然后将UTC时间解析为本地时间(标记为本地时间)……通过切换样式,你告诉它解析这个时间并将其标记为UTC。 - John Sobolewski
好的,所以调试器是根据我的服务器进行翻译的。嗯,所以你使用跟踪来调试是因为这个原因? - u84six
所以即使它以通用格式输入,如果我想要显示它,我仍然需要将其转换为通用格式?奇怪的实现方式,但我想我可以处理它。 - u84six
调试器很可能使用ToString来翻译您看到的内容,这比它内部存储的表示时间/类型等的任何数字更有用... - John Sobolewski

10
注意,这是多年后的答案,但我今天看到了它,并且一旦解决了我的问题,我想添加一些其他答案中没有提到的上下文。
回到原始贴中的代码片段,它无法像原作者期望的那样将UTC时间字符串作为UTC DateTime 存储,这是因为 DateTimeStyles.AssumeUniversal 仅指定输入字符串是UTC字符串。在C#中,默认情况下,将创建 DateTime 作为DateTimeKind.Local。另一个答案中指出了这一点。这意味着将时间从UTC转换为本地时间。
为确保最终结果是UTC DateTime,您需要使用 DateTimeStyles.AdjustToUniversalDateTimeStyles。其他答案中也提到了这一点。但是,如果您的输入字符串没有明显的时区,则可能被认为是本地时间,然后从本地时间转换为UTC。
幸运的是,DateTimeStyles实际上是一个标志枚举,这意味着我们可以同时使用上述两个选项。例如:
DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ",    CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);

1
DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal working! And testDate.Date.Kind is also good -> DateTimeKind.Utc - marbel82

5
你应该使用 DateTimeStyles.AdjustToUniversal。输入的 DateTime 已经是通用时间,而 AdjustToUniversal 枚举选项将把输入转换为本地时间,但结果的 Kind 为 DateTimeKind.Unspecified

1
种类实际上是“本地(Local)”,而不是“未指定(Unspecified)”状态。 - John Sobolewski
有趣...文档说的不一样。虽然需要考虑的是,日期和时间问题可能会引起数小时的痛苦。 - Steve Danner
是的,我几乎认为你应该始终使用DateTimeOffSet,以清楚地了解“本地”实际上意味着什么。 请参阅:http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx - John Sobolewski

3

如果你使用AssumeUniversal,你的服务器时区将会被转换为UTC时间。那么你的服务器时区可能是东部标准时间(EST)。


嗯,让我试着不带风格来翻译。 - u84six
那并没有解决问题。日期和时间仍然有偏移。 - u84six

2
我建议使用.AssumeLocal而不是.AssumeUniversal
如果你有一个未知时区的时间戳,并且你知道这个时间戳是指发生在你当地时区的事件,那么你应该告诉解析器将时间戳视为本地时间(即在你的时区)。
通过使用.AssumeUniversal,你正在指示解析器将时间戳视为UTC时间戳,因此当你使用本地时区显示它时,它会自动偏移相应的数量。 编辑: 一个重要的事情:时间戳中的大写字母“Z”表明它是一个UTC时间戳,这意味着你确实想将其视为通用时间。如果你想将其视为本地时间戳,则应从时间戳和相应的解析字符串中删除“Z”。
参考:http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx#KSpecifier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接