ChatGPT解决这个技术问题 Extra ChatGPT

如何从 ISO 8601 格式创建 .NET DateTime

我找到了如何将 DateTime 转换为 ISO 8601 格式,但没有关于如何在 C# 中执行相反的操作。

我有 2010-08-20T15:00:00Z,我想把它变成一个 DateTime 对象。

我可以自己分离字符串的各个部分,但对于已经成为国际标准的东西来说,这似乎需要做很多工作。

Convert String to Date in .NET 的可能重复项
@abatishchev,这就是为什么它不是重复的。 “重复”中的答案不处理 8601。
是的,这不是重复的。这个问题特定于解析 ISO 8601 格式。

P
Peter Mortensen

此解决方案利用 DateTimeStyles 枚举,它也适用于 Z。

DateTime d2 = DateTime.Parse("2010-08-20T15:00:00Z", null, System.Globalization.DateTimeStyles.RoundtripKind);

这完美地打印了解决方案。


DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind); 的编辑解决方案似乎运行良好。
任何希望详细说明此 DateTimeStyles.RoundtripKind? MSDN 描述的人都是空白的。
似乎对这个问题进行了编辑以反映更好的答案,但由于@MamtaD 覆盖了原始答案,因此评论变得非常具有误导性。一开始我不确定答案是否正确,因为上面的评论,但后来我意识到错误的答案后来被正确的取代了
小数位数对我不起作用。 2018-06-19T14:56:14.123Z 被解析为本地时间,而不是 UTC。我使用 CultureInfo.InvariantCulture 而不是 null。
有关 DateTimeStyles.RoundTripKind 的详细信息,请参阅 stackoverflow.com/q/39572395/2014893
A
Alexey Biryukov

尽管 MSDN 说“s”和“o”格式反映了标准,但它们似乎只能解析它的有限子集。如果字符串包含时区规范,尤其是它是一个问题。 (对于基本的 ISO8601 格式或降低精度的格式,它都不是——但这不完全是你的情况。)这就是为什么我在解析 ISO8601 时使用自定义格式字符串的原因。目前我首选的片段是:

static readonly string[] formats = { 
    // Basic formats
    "yyyyMMddTHHmmsszzz",
    "yyyyMMddTHHmmsszz",
    "yyyyMMddTHHmmssZ",
    // Extended formats
    "yyyy-MM-ddTHH:mm:sszzz",
    "yyyy-MM-ddTHH:mm:sszz",
    "yyyy-MM-ddTHH:mm:ssZ",
    // All of the above with reduced accuracy
    "yyyyMMddTHHmmzzz",
    "yyyyMMddTHHmmzz",
    "yyyyMMddTHHmmZ",
    "yyyy-MM-ddTHH:mmzzz",
    "yyyy-MM-ddTHH:mmzz",
    "yyyy-MM-ddTHH:mmZ",
    // Accuracy reduced to hours
    "yyyyMMddTHHzzz",
    "yyyyMMddTHHzz",
    "yyyyMMddTHHZ",
    "yyyy-MM-ddTHHzzz",
    "yyyy-MM-ddTHHzz",
    "yyyy-MM-ddTHHZ"
    };

public static DateTime ParseISO8601String ( string str )
{
    return DateTime.ParseExact ( str, formats, 
        CultureInfo.InvariantCulture, DateTimeStyles.None );
}

如果您不介意解析无 TZ 字符串(我愿意),您可以添加一个“s”行来大大扩展涵盖的格式更改的数量。


我会在 formats 数组中添加 "yyyyMMdd" 以将精度降低到几天,因为有时 RFC 5545 RRULE 将依赖 DTSTART 来提供时间。
使用 K 允许您将不同的时区处理组合在一起。我在 stackoverflow.com/a/31246449/400547 有一个更广泛的变体,但它是否过于广泛(接受有效的 ISO 8601 但未在更常见的配置文件中使用的东西)但它确实显示了 K 如何将大小减少三分之一。
a
abatishchev
using System.Globalization;

DateTime d;
DateTime.TryParseExact(
    "2010-08-20T15:00:00",
    "s",
    CultureInfo.InvariantCulture,
    DateTimeStyles.AssumeUniversal, out d);

在 LinqPad 中产生 False 和 d ~~> "1/1/0001 12:00:00 AM" :(
@Reb:“2010-08-20T15:00:00”和“s”,如果最后没有“Z”
已更正:) Z 出现在我的所有样本中(恰好来自各种 GPS 单元和 GPX 文件)
在另一个 ISO 8601 参考文献中发现“Z”代表区域——就像在时区中一样。
Z 实际上代表祖鲁时间或 UTC。 en.wikipedia.org/wiki/ISO_8601#UTC
P
Peter Mortensen

这是一个更适合我的版本(LINQPad 版本):

DateTime d;
DateTime.TryParseExact(
    "2010-08-20T15:00:00Z",
    @"yyyy-MM-dd\THH:mm:ss\Z",
    CultureInfo.InvariantCulture,
    DateTimeStyles.AssumeUniversal, 
    out d);
d.ToString()

生产

true
8/20/2010 8:00:00 AM

目前在我的单元测试中使用它来验证我希望成为日期的所有字符串都是 Iso8601 格式。谢谢!
为什么这会返回一个不是 UTC 的时间戳?!相当大地违反了最小惊讶原则,因为“AssumeUniversal”的“不变文化”不应该这样做,因为 DST 在世界范围内的差异如此之大,因此如果您开始运行代码,返回您当地的主要时区可能会引入错误在具有不同设置的服务器上!
A
AlexB

完全匹配 ISO 字符串的格式以使 TryParseExact 起作用似乎很重要。我猜Exact就是Exact,这个答案对大多数人来说都是显而易见的,但无论如何......

就我而言,Reb.Cabin 的回答不起作用,因为我的输入与下面的“值”略有不同。

值:2012-08-10T14:00:00.000Z

毫秒内有一些额外的 000,可能还有更多。

但是,如果我在格式中添加一些 .fff,如下所示,一切都很好。

格式字符串:@"yyyy-MM-dd\THH:mm:ss.fff\Z"

在 VS2010 立即窗口中:

DateTime.TryParseExact(value,@"yyyy-MM-dd\THH:mm:ss.fff\Z", CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal, out d);

真的

您可能还必须使用 DateTimeStyles.AssumeLocal,具体取决于您的时间所在的区域...


这对我有用,但我还必须将 AssumeUniversal 更改为 AdjustToUniversal
Z
Zar Shardan

这在 LINQPad4 中运行良好:

Console.WriteLine(DateTime.Parse("2010-08-20T15:00:00Z"));
Console.WriteLine(DateTime.Parse("2010-08-20T15:00:00"));
Console.WriteLine(DateTime.Parse("2010-08-20 15:00:00"));

a
abatishchev

DateTime.ParseExact(...) 允许您告诉解析器每个字符代表什么。


任何对此投反对票的人,请说明您这样做的原因。即使是糟糕的答案也有利于学习。