【问题标题】:Why can't DateTime.Parse parse UTC date为什么 DateTime.Parse 不能解析 UTC 日期
【发布时间】:2009-11-18 15:06:43
【问题描述】:

为什么它不能解析这个:

DateTime.Parse("Tue, 1 Jan 2008 00:00:00 UTC")

【问题讨论】:

  • 当您在 Javascript 中使用 new Date().toUTCString() 时,IE9 仍然错误地添加“UTC”
  • 对于 2009 年来此帖子的任何人,此问题的答案是 momentjs.com

标签: c# datetime parsing


【解决方案1】:

假设您使用“o”格式作为日期时间,因此您有“2016-07-24T18:47:36Z”,有一个非常简单的方法来处理这个问题。

致电DateTime.Parse("2016-07-24T18:47:36Z").ToUniversalTime()

当您调用DateTime.Parse("2016-07-24T18:47:36Z") 时会发生什么,您会得到一个设置为本地时区的DateTime。因此它将其转换为当地时间。

ToUniversalTime() 将其更改为 UTC DateTime 并将其转换回 UTC 时间。

【讨论】:

  • 假设当您将 Zulu 发送到 Web api 时会发生这种情况,但您看到它显示为当地时间。认为刚刚点击了某些东西,谢谢
【解决方案2】:

就用那个吧:

var myDateUtc = DateTime.SpecifyKind(DateTime.Parse("Tue, 1 Jan 2008 00:00:00"), DateTimeKind.Utc);

if (myDateUtc.Kind == DateTimeKind.Utc)
{
     Console.WriteLine("Yes. I am UTC!");
}

您可以使用在线 c# 编译器测试此代码:

http://rextester.com/

希望对你有帮助。

【讨论】:

  • 我真的有点惊讶没有DateTime.Parse("Some:Time:here", "Utc")的方法
【解决方案3】:

它无法解析该字符串,因为“UTC”不是有效的时区指示符。

UTC 时间通过在时间字符串的末尾添加“Z”来表示,因此您的解析代码应如下所示:

DateTime.Parse("Tue, 1 Jan 2008 00:00:00Z");

来自Wikipedia article on ISO 8601

如果时间是 UTC,则添加“Z” 直接在没有时间之后 空间。 “Z”是区域代号 零 UTC 偏移量。 “09:30 UTC”是 因此表示为“09:30Z”或 “0930Z”。 “14:45:15 UTC”将是 “14:45:15Z”或“144515Z”。

UTC 时间也称为“祖鲁”时间, 因为“祖鲁”是北约的语音 “Z”的字母词。

【讨论】:

  • 我示例中的日期字符串来自 Internet Explorer
  • @Dave:当你说它来自IE时,你的意思是你从网页中提取它吗?您可能必须为提取 UTC 并将其替换为 Z 的 DateTime 解析器编写自己的替换。
  • 在针对 FF 进行测试时,我忘记了在我 POST 回服务器的日期调用了 toUTCString() 方法。 FF 发送 GMT,而 IE 发送 UTC。所以这一次我不能怪 IE……!
  • 正如其他答案所指出的,带有 Z 指示符的 UTC 日期字符串确实会成功解析,但它也会被转换为本地时间,即它返回 DateTime带有KindLocal 和调整的时间戳。要始终获得 UTC DateTime,可以使用@crokusek 建议的DateTime.Parse("2008-01-01 00:00:00Z", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal) 之一,或@ruffin 建议的DateTimeOffset.Parse("2008-01-01 00:00:00Z").UtcDateTime
  • 奇怪的是,DateTime.Parse("Tue, 1 Jan 2008 00:00:00Z").Kind 返回的是 Local,而不是 Utc
【解决方案4】:

或在调用中使用 AdjustToUniversal DateTimeStyle

DateTime.ParseExact(String, String[], IFormatProvider, DateTimeStyles)

【讨论】:

  • 这确实有效。我使用此代码并从 UTC 字符串中获得了正确的 UTC DateTime: DateTime.TryParseExact("2012-01-30T00:28:00Z", "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out时间值));
  • 这个也可以,Utc 进出,不需要格式,不需要 Z:DateTime.Parse("8/3/2013 1:02:41 AM", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
  • 我正在处理类似于 Roboblob 的 UTC 时间字符串,并使用类似于 Roboblob 指定的代码来维护值的 UTC 特性:DateTime.ParseExact(utcTimeStringINeeededToParse, "yyyy-MM-ddTHH :mm:ss.0000000Z", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AdjustToUniversal)
【解决方案5】:

要正确解析问题中给出的字符串而不更改它,请使用以下内容:

using System.Globalization;

string dateString = "Tue, 1 Jan 2008 00:00:00 UTC";
DateTime parsedDate = DateTime.ParseExact(dateString, "ddd, d MMM yyyy hh:mm:ss UTC", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal);

此实现使用字符串来指定正在解析的日期字符串的确切格式。 DateTimeStyles 参数用于指定给定字符串是协调的通用时间字符串。

【讨论】:

  • 根据docs,“返回的DateTime值的Kind属性为DateTimeKind.Local。” ParseExact 正确地将其解析为 UTC,然后在返回之前将其转换为本地时间。如果您希望返回的值原封不动地返回为 UTC,请使用 DateTimeStyles.RoundtripKind
【解决方案6】:

你需要指定格式:

DateTime date = DateTime.ParseExact(
    "Tue, 1 Jan 2008 00:00:00 UTC", 
    "ddd, d MMM yyyy HH:mm:ss UTC", 
    CultureInfo.InvariantCulture);

【讨论】:

  • 不错的建议,但如果提供的日期字符串末尾不包含 UTC,这将失败。假设您传递了一个末尾有 +01 的日期字符串,这将导致 FormatException。我想这取决于他想做什么。
【解决方案7】:

我整理了一个实用方法,它使用了此处显示的所有技巧以及更多技巧:

    static private readonly string[] MostCommonDateStringFormatsFromWeb = {
        "yyyy'-'MM'-'dd'T'hh:mm:ssZ",  //     momentjs aka universal sortable with 'T'     2008-04-10T06:30:00Z          this is default format employed by moment().utc().format()
        "yyyy'-'MM'-'dd'T'hh:mm:ss.fffZ", //  syncfusion                                   2008-04-10T06:30:00.000Z      retarded string format for dates that syncfusion libs churn out when invoked by ejgrid for odata filtering and so on
        "O", //                               iso8601                                      2008-04-10T06:30:00.0000000
        "s", //                               sortable                                     2008-04-10T06:30:00
        "u"  //                               universal sortable                           2008-04-10 06:30:00Z
    };

    static public bool TryParseWebDateStringExactToUTC(
        out DateTime date,
        string input,
        string[] formats = null,
        DateTimeStyles? styles = null,
        IFormatProvider formatProvider = null
    )
    {
        formats = formats ?? MostCommonDateStringFormatsFromWeb;
        return TryParseDateStringExactToUTC(out date, input, formats, styles, formatProvider);
    }

    static public bool TryParseDateStringExactToUTC(
        out DateTime date,
        string input,
        string[] formats = null,
        DateTimeStyles? styles = null,
        IFormatProvider formatProvider = null
    )
    {
        styles = styles ?? DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal; //0 utc
        formatProvider = formatProvider ?? CultureInfo.InvariantCulture;

        var verdict = DateTime.TryParseExact(input, result: out date, style: styles.Value, formats: formats, provider: formatProvider);
        if (verdict && date.Kind == DateTimeKind.Local) //1
        {
            date = date.ToUniversalTime();
        }

        return verdict;

        //0 employing adjusttouniversal is vital in order for the resulting date to be in utc when the 'Z' flag is employed at the end of the input string
        //  like for instance in   2008-04-10T06:30.000Z
        //1 local should never happen with the default settings but it can happen when settings get overriden   we want to forcibly return utc though
    }

注意“-”和“T”(单引号)的使用。这是最佳实践,因为区域设置会干扰对字符的解释,例如“-”,导致其被解释为“/”或“。”或任何您的区域设置表示为日期组件分隔符。我还包含了第二种实用方法,它展示了如何解析从 Web 客户端提供给 rest-api 后端的最常见的日期字符串格式。享受吧。

【讨论】:

    【解决方案8】:

    只需将“UTC”替换为“GMT”——简单且不会破坏格式正确的日期:

    DateTime.Parse("Tue, 1 Jan 2008 00:00:00 UTC".Replace("UTC", "GMT"))
    

    【讨论】:

      【解决方案9】:

      这不是一个有效的格式,但是“Tue, 1 Jan 2008 00:00:00 GMT”是。

      文档是这样说的:

      包含时区信息并符合 ISO 8601 的字符串。例如,以下两个字符串中的第一个指定协调世界时 (UTC);第二个指定时区的时间比 UTC 早 7 小时:

      2008-11-01T19:35:00.0000000Z

      包含 GMT 指示符并符合 RFC 1123 时间格式的字符串。例如:

      格林威治标准时间 2008 年 11 月 1 日星期六 19:35:00

      包含日期和时间以及时区偏移信息的字符串。例如:

      03/01/2009 05:42:00 -5:00

      【讨论】:

      • 在与此格式类似的日期字符串中将“UTC”简单替换为“GMT”效果很好,感谢您的提示。
      • 虽然请注意,这会为我返回一个 DateTimeKindLocal。看起来解决方法是使用DateTimeOffset.Parse(然后是x.UtcDateTime),如果你想确保你在解析过程中不会从UTC旅行车上掉下来。
      【解决方案10】:

      不知道为什么,但您可以将 DateTime.ToUniversalTime 包装在 try / catch 中,并在更多代码中实现相同的结果。

      祝你好运。

      【讨论】:

      • ToUniversalTime 从不抛出异常
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多