DateTime和Offset Subtlety

时间:2016-11-10 17:12:06

标签: c# datetime

我正在DateTime研究BCL及相关课程的“机制”。 我对以下奇怪的行为感兴趣。请考虑以下代码段:

var dt1 = new DateTime(2014, 10, 24, 15, 30, 00, DateTimeKind.Unspecified);
DateTimeOffset dto2 = new DateTimeOffset(dt1, TimeSpan.FromHours(6));
string input = dto2.ToString("o");
DateTime dt6 = DateTime.Parse(input, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
Console.WriteLine("DT6:" + dt6.ToString("o"));

我知道我应该将字符串解析为DateTimeOffset,但我只是想知道为什么库允许我做我在这里做的事情,最有趣的是为什么输出将是:{{1 }} 它在解析过程中所做的是它将偏移量设置为我本地机器时区中给定时间段的实际偏移量,并将小时数调整为初始偏移量与结果偏移量之间的差值。 无论我提供什么"DT6:2014-10-24T13:30:00.00000000+04:00"选项,它都会这样做。结果值的类型设置为DateTimeStyles,无论我是否提供Local值。 所以问题是为什么默认情况下它将类型设置为Roundtrip,第二个问题是Local存储偏移量的位置,如果它存储它,为什么我们需要DateTime类呢?

1 个答案:

答案 0 :(得分:1)

一些事情:

  • DateTimeDateTimeOffset都是结构,而不是类。它们是value types

  • 您的问题归结为理解DateTime.Parse方法的行为 - 而不是DateTime结构。我建议为该方法阅读the docs。那里有很多好的信息描述了你所看到的行为的微妙之处。

  • 文档可以说明返回类型in the "Return value" section(强调我的):

      

    通常,Parse方法返回一个Date属性对象,其Kind属性为DateTimeKind.Unspecified但是, Parse方法也可以执行时区转换,并以不同的方式设置Kind属性的值,具体取决于s和{{1的值参数:

         

    chart

    您在styles参数中传递"2014-10-24T15:30:00.0000000+06:00"的值,其中包含时区偏移,因此您受到图表中第一行的影响,并且结果将转换为您机器的本地时区,无论可能是什么。

  • s标志不会对此产生任何影响。如果您的输入以DateTimeStyles.RoundTripKind而不是偏移量结束,那么您只会看到效果,以便应用上图中的第三行。在这种情况下,Z标志会确保RoundTripKind。没有它,你仍然得到DateTimeKind.Utc

  • 不存储偏移量。 DateTimeKind.Local存储的唯一内容是将DateTimeTicks属性合并为一个64-bit private field的值。

    作为一个有趣的旁注,请注意,由于此字段的两个位是为Kind保留的,因此有四个可能的状态,即使只有三个Kind值被暴露。事实上,有一种隐藏的第四种类型,在"日期时间的深黑暗秘密"在this articlein the references sources中。 (基本上,它是DateTimeKind的变体。)

  • 如果您想要更合理的日期/时间API,请考虑使用Noda Time