DateTimeStyles.RoundtripKind枚举是什么意思?

我正在阅读回答者的post, 在这里我遇到了这个我想要了解的枚举器DateTimeStyles.RoundtripKind 。 我查看了MSDN ,其中说:

使用“o”或“r”标准格式说明符将DateTime对象转换为字符串时,将保留日期的DateTimeKind字段,然后将该字符串转换回DateTime对象。

我引用的post中输入的时间戳如下:

  

我运行她的代码,它仍然有效。 现在连接我所拥有的所有信息都是一团糟:

  1. 上述时间戳包含一些标识符T
  2. MSDN文档讨论了or格式说明符,它没有说明它是什么?
  3. 如果你在上面引用的MSDN链接上深入挖掘有关DateTimeKind枚举的更多细节,它就没有提及or格式说明符。 以下链接说:

     Member Name | Description -------------------------------------------------------------------------------- Local | The time represented is local time. Unspecified | The time represented is not specified as either local time or Coordinated Universal Time (UTC). Utc | The time represented is UTC. 

PS我尝试在上面创建一个表,但似乎SO没有创建表格结构的原生支持。

那么有人可以帮我理解DateTimeStyles.RoundtripKind枚举及其工作原理吗?

所以我终于能够理解这一点并在此处分享相同的信息,如果它对其他人也有帮助:

第一部分是将C#DateTime对象转换为字符串。 有许多格式说明符可以做到这一点,但对于我们来说,“r”和“o”格式说明符与DateTimeStyles.RoundtripKind 。 您可以在此处查看所有日期时间格式说明符。 看看使用这些格式说明符在代码中进行转换时会发生什么:

 //r corresponds to RFC 1123 format (GMT date time format) var gmtDateTimeString = DateTime.Now.ToString("r"); //gives Fri, 23 Sep 2016 15:39:21 GMT //o corresponds to ISO 8601 (Local date time format) var localDateTimeString = DateTime.Now.ToString("o"); //gives 2016-09-23T15:39:21.8899216+05:30 

您可以清楚地看到输出的字符串日期时间内嵌有信息,这表明:

  • Fri, 23 Sep 2016 15:39:21 GMTDateTimeKind.Utc (“GMT”文本存在)
  • 2016-09-23T15:39:21.8899216+05:30表示DateTimeKind.Local的日期时间(根据ISO 8601标准,“T”字符存在)

现在是第二部分。 如果我要将这些日期时间字符串gmtDateTimeStringlocalDateTimeString回日期时间对象,那么我们需要解析它们。 因此,在传递给DateTime.Parse API的DateTimeStyles.RoundtripKind枚举值的帮助下,您实际上表示时区信息已经在字符串中烘焙,并且API使用该信息适当地解析日期时间。

通常,当日期时间数据以XML格式通过线路传输时,我使用的是ISO 8601格式,我在post中看到了这个格式,我在post中提到了这个问题。 因此,在解析从XML文档获取的这样的日期时间字符串时,使用DateTimeStyles.RoundtripKind根据字符串中存在的时区信息获取正确的日期时间值是合适的。

我很难理解其他答案,所以我决定自己做一些研究。 幸运的是,.NET库的源代码可以在线获得。

DateTimeStyles.RoundTripKind在源代码中有注释 :

 // Attempt to preserve whether the input is unspecified, local or UTC 

它或多或少与DateTimeStyles.RoundTripKind上的MSDN文档一样模糊:

使用“o”或“r”标准格式说明符将DateTime对象转换为字符串时,将保留日期的DateTimeKind字段,然后将该字符串转换回DateTime对象。

通过浏览Reference Source网站,可以看出DateTimeStyles.RoundTripKind的使用非常少。 基本上,如果设置了标志,那么它可以将DateTime的类型修改为DateTimeKind.Utc 。 所以这是设置此标志的效果:有时解析的DateTime值的Kind属性设置为Utc

究竟何时发生这种情况由内部标志ParseFlags.TimeZoneUtc 。 确定何时设置此标志会更复杂,但据我所知,如果使用ZGMT指定时区,解析器将设置此标志。 在源代码中有关于此的评论 :

 // NOTENOTE : for now, we only support "GMT" and "Z" (for Zulu time). 

我的结论是,如果使用or格式化时间戳,并且在解析时间戳时使用DateTimeUtc如果字符串中的时区是UTC时区,则将得到的DateTime值的Kind设置为Utc

但是,当没有设置标志时会发生什么? 确定这一点的最佳方法是对两个格式说明符进行一些实际测试。

往返(“O”,“o”)格式说明符

使用o格式说明符时,时间戳的时区将为Z表示UTC或+/-与UTC的偏移量(例如, 2017-02-26T22:55:15.4923368+01:00 )。 这是一个表,显示从往返时间戳解析的DateTime值的Kind属性的值:

时区|  RoundTripKind | 类
 --------- + --------------- + ------
 “Z”| 未指定| 本地
 “Z”| 指定| 世界标准时间
不是“Z”| 未指定| 本地
不是“Z”| 指定| 本地

如果要以往返格式解析时间戳并且您希望时间戳的时区为UTC,则应指定DateTimeStyles.RoundTripKind以确保解析的DateTime值具有类型Utc

RFC1123(“R”,“r”)格式说明符

使用r格式说明符时,时间戳将始终包含GMT (即使原始DateTime类型不是Utc ),因此r格式的表不需要Timezone列。 但是,我发现在解析RFC1123时间戳时, DateTime.ParseDateTime.ParseExact行为有所不同:

方法|  RoundTripKind | 类
 ----------- + --------------- + ------------
解析| 未指定| 本地
解析| 指定| 世界标准时间
 ParseExact | 未指定| 不明
 ParseExact | 指定| 不明

使用Parse方法时,RFC1123格式的时间戳与往返格式的UTC时间戳相同。 但是,由于某种原因, ParseExact方法忽略DateTimeStyles.RoundTripKind标志。 解析往返格式化时间戳时不是这种情况。

如果要解析RFC1123格式的时间戳,则应使用Parse方法并指定DateTimeStyles.RoundTripKind或者如果您更喜欢ParseExact方法,则必须将已解析时间戳的类型修改为Utc 您可以使用DateTime.SpecifyKind方法创建新的时间戳。

结论

解析往返和RFC1123时间戳时,请指定DateTimeStyles.RoundTripKind以确保解析的DateTime值的Kind属性为Utc

如果往返时间戳具有非零偏移,那么您必须将时间戳解析为DateTimeOffset值以保留偏移量( Local不会告诉您偏移量是什么 – 只是它可能与0不同)。

不要使用DateTime.ParseExact来解析RFC1123时间戳(或者在解析时间戳后将类型更改为Utc )。

往返格式用于“机器消耗” – 可以轻松地将其解析回相同的DateTime值。
大多数其他格式用于“人类消费”,以向人显示日期(可能包括时间)。