【问题标题】:C# DateTime.Parse(String) returns different value in different systemC# DateTime.Parse(String) 在不同的系统中返回不同的值
【发布时间】:2020-05-29 00:21:18
【问题描述】:

今天,我观察到DateTime.Parse(String) 方法在不同服务器上运行时出现了一些奇怪的行为。这可以在不同的在线 C# 编译器中观察到。

我的输入格式为yyyy-MM-ddTHH:mm:ssZ。示例:让我们使用 2020-02-12T16:57:36Z 转换为刻度是:637171234560000000(使用 https://tickstodatetime.azurewebsites.net/ 转换)

这是我用于测试此行为的代码:

DateTime parsedDateTime = DateTime.Parse("2020-02-12T16:57:36Z");
Console.WriteLine(parsedDateTime + " " + parsedDateTime.Kind.ToString() + " " + parsedDateTime.Ticks);

https://dotnetfiddle.net/akuyiI 上,它返回02/12/2020 16:57:36 Local 637171234560000000

https://rextester.com/XWH12209 上,它返回12.02.2020 17:57:36 Local 637171270560000000

我知道DateTime被解析为本地时区并以本地时间显示,但是为什么系统之间的滴答数也不同?

【问题讨论】:

  • 那些刻度代表的时间正好相隔一小时,这表明这是一个时区问题(不是夏令时,除非你碰巧在南半球......)

标签: c# datetime


【解决方案1】:

这与您运行的服务器的 CultureInfo 有关。 DateTime.Parse 具有不同的重载和解析日期时间以及货币,这取决于系统的 CultureInfo(语言和地区等)

【讨论】:

  • 其实不是这样的。字符串 conforming to ISO8601 应该被解析为 UTC 时间,即使它随后被调整为本地时间)。
【解决方案2】:

解析日期的不同时区的可能解决方案是:

DateTime parsedDateTime = DateTime.Parse(
    "2020-02-12T16:57:36Z", 
    CultureInfo.InvariantCulture, 
    DateTimeStyles.AdjustToUniversal);

【讨论】:

    【解决方案3】:

    yyyy-MM-ddTHH:mm:ssZ 格式的字符串表示a date in UTC
    它被正确解析为这样,但不幸的是,生成的DateTimeis DatetimeKind.Local,并且它的值会根据计算机的时区进行相应调整。

    正如DateTime source code file开头的评论所述,

    Starting from V2.0, DateTime also stored some context about its time
    zone in the form of a 3-state value representing Unspecified, Utc or
    Local. This is stored in the two top bits of the 64-bit numeric value
    with the remainder of the bits storing the tick count. This information
    is only used during time zone conversions and is not part of the
    identity of the DateTime. Thus, operations like Compare and Equals
    ignore this state. This is to stay compatible with earlier behavior
    and performance characteristics and to avoid forcing  people into dealing
    with the effects of daylight savings. Note, that this has little effect
    on how the DateTime works except in a context where its specific time
    zone is needed, such as during conversions and some parsing and formatting
    cases.
    

    因此,DatetimeKind.Local 日期的 Ticks 属性相对于 本地 12:00:00 midnight, January 1, 0001,而不是相对于 UTC 12:00:00 midnight, January 1, 0001
    这在remarks for the Ticks property 中有记录。

    这也意味着通过这种DateTime.Parse 在不同时区的不同服务器上获得的两个日期实例将比较为“不相等”,即使它们源自描述相同 UTC 日期的相同字符串。这是为了向后兼容。

    为了直接比较刻度,您需要先将convert 两个日期与Kind.UTC 相比较。

    【讨论】:

    • "Ticks 属性.. 是相对于本地 [时间]" - 这是关键! ;) 将Console.WriteLine(TimeZoneInfo.Local); 添加到代码中可以明显看出区别在哪里...
    【解决方案4】:

    答案已经在问题中。关键点在输出:12.02.2020 17:57:36 Local 637171270560000000

    dateTime.kind 显示它是什么类型的日期?由于这两个网站很可能位于两个不同的地方,因此它显示了两个不同的时间,因为 .net 已将给定的 UTC 时间转换为本地时间,这通过 DateTime.Kind 反映出来。

    如果你改为运行这个

    DateTime parsedDateTime = DateTime.Parse("2020-02-12T16:57:36Z").ToUniversalTime();
    Console.WriteLine(parsedDateTime + " " + parsedDateTime.Kind.ToString() + " " + parsedDateTime.Ticks);
    

    https://rextester.com/XWH12209

    https://dotnetfiddle.net/o4XRFS

    您将获得相同的日期/时间组合,因为现在它没有转换为本地日期时间,而是转换为 UTC。

    当我在本地机器上运行你的代码时,我的输出是:

    20 年 2 月 12 日晚上 10:57:36 本地 637171450560000000

    这基本上意味着在我的国家/地区,在给定的 UTC 时间是 20 年 2 月 12 日晚上 10:57:36。

    【讨论】:

      猜你喜欢
      • 2017-02-20
      • 2021-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-18
      相关资源
      最近更新 更多