DateTimeStyles.RoundtripKind枚举是什么意思?

What does DateTimeStyles.RoundtripKind enumeration mean?

我正在阅读这个答案 where I came across this enumeration value DateTimeStyles.RoundtripKind. I'm trying to understand it now. I looked into MSDN docs here 上面写着:

The DateTimeKind field of a date is preserved when a DateTime object is converted to a string using the "o" or "r" standard format specifier, and the string is then converted back to a DateTime object.

我在上一段提到的post中input变量指向的时间戳如下:

<timestamp time='2016-09-16T13:45:30'>

我运行她的代码并且有效。现在关联我拥有的所有信息变得有点混乱:

  1. 上面的时间戳包含一些标识符T

  2. MSDN 文档讨论了 or 格式说明符,它没有说明它是什么?

  3. 如果您在 MSDN link 上深入了解 DateTimeKind 枚举的更多详细信息,我在上面引用过,它没有提到 or 格式说明符。 Here 是 link 表示:

    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.
    

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

往返格式适用于 "machine consumption" - 它可以很容易地解析回相同的 DateTime 值。
大多数其他格式用于 "human consumption",向某人显示日期(可能包括时间)。

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

第一部分是将 C# DateTime 对象转换为字符串。有很多格式说明符可以做到这一点,但对我们来说 ro 格式说明符是我们关心的关于 DateTimeStyles.RoundtripKind。您可以看到所有日期时间格式说明符 here。看看当我们使用这些格式说明符在代码中进行转换时会发生什么:

//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

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

  • 2016 年 9 月 23 日,星期五 15:39:21 GMTDateTimeKind.UtcGMT 文本存在)
  • 2016-09-23T15:39:21.8899216+05:30表示日期时间DateTimeKind.LocalT 字符按照 ISO 8601 标准存在)

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

通常,当日期时间数据以 XML 格式通过网络传输时,会使用 ISO 8601 格式,我在 post 中看到我在此线程中 post 提出问题之前提到过。因此,在解析从 XML 文档中获取的此类日期时间字符串时,使用 DateTimeStyles.RoundtripKind 来根据时间获取正确的日期时间值是合适的-字符串中存在区域信息。

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

DateTimeStyles.RoundTripKind has a comment in the source:

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

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

The DateTimeKind field of a date is preserved when a DateTime object is converted to a string using the "o" or "r" standard format specifier, and the string is then converted back to a DateTime object.

通过浏览 Reference Source 网站可以看出 DateTimeStyles.RoundTripKind 很少使用。本质上,如果设置了标志,则 it may modify the kind of the DateTime to DateTimeKind.Utc。所以这是设置这个标志的效果:有时解析的 DateTime 值的 Kind 属性 设置为 Utc.

发生这种情况的确切时间由内部标志控制 ParseFlags.TimeZoneUtc. It is more complicated to determine when this flag gets set but as far as I can tell the parser will set this flag if the timezone is specified using either Z or GMT. There is a comment about this in the source code:

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

我的结论是,如果使用 or 格式化时间戳,并且在解析时间戳时使用 DateTimeStyles.RoundTripKind,则结果 Kind =15=] 如果字符串中的时区是 UTC 时区,则值设置为 Utc

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

往返("O"、"o")格式说明符

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

Timezone | RoundTripKind | Kind
---------+---------------+------
"Z"      | Not specified | Local
"Z"      | Specified     | Utc
Not "Z"  | Not specified | Local
Not "Z"  | Specified     | Local

如果你想解析往返格式的时间戳并且你希望时间戳的时区是UTC那么你应该指定DateTimeStyles.RoundTripKind以确保解析的DateTime 值有种类 Utc.

RFC1123("R"、"r")格式说明符

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

Method     | RoundTripKind | Kind
-----------+---------------+------------
Parse      | Not specified | Local
Parse      | Specified     | Utc
ParseExact | Not specified | Unspecified
ParseExact | Specified     | Unspecified

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

如果你想解析 RFC1123 格式的时间戳,你应该使用 Parse 方法并指定 DateTimeStyles.RoundTripKind 或者如果你更喜欢 ParseExact 方法将不得不修改解析时间戳的类型为Utc。您可以通过使用 DateTime.SpecifyKind 方法创建一个新的时间戳来做到这一点。

结论

在解析round-trip和RFC1123时间戳时指定DateTimeStyles.RoundTripKind以确保解析的DateTime值的Kind属性为Utc

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

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