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


130

我已经找到了如何将DateTime转换为ISO 8601格式,但是在C#中如何进行相反操作却一无所获。

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

我可以自己将字符串的各个部分分开,但是对于已经是国际标准的东西来说,这似乎需要大量工作。


1
中将

1
@爱丁:2010年8月24日在12:02
abatishchev

@Aidin:是的,这是重复的。唯一的格式差异。其余部分相同。
abatishchev

6
@abatishchev,这就是为什么它不是重复的原因。在“重复”答案不处理8601
旋毛虫

3
是的,这不是重复的。此问题特定于解析ISO 8601格式。
何塞

Answers:


142

该解决方案利用了DateTimeStyles枚举,并且还与Z一起使用。

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

这样可以完美打印解决方案。


3
编辑的解决方案DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);似乎效果很好。
j3ko 2012年

4
任何希望对此DateTimeStyles.RoundtripKind? MSDN描述进行详细说明的人都是空白。
史蒂夫·帕里斯

8
似乎已对该问题进行了编辑以反映出更好的答案,但是由于@MamtaD覆盖了原始答案,因此注释变得极具误导性。刚开始时,由于顶部的注释,我不确定答案是否正确,但是后来我意识到错误的答案后来被正确的答案所取代
Aidin 2015年

5
小数位数对我不起作用。2018-06-19T14:56:14.123Z被解析为本地时间,而不是UTC。我使用CultureInfo.InvariantCulture而不是null。
埃里克·哈特

1
有关更多信息DateTimeStyles.RoundTripKind,请参见stackoverflow.com/q/39572395/2014893
Robert K. Bell

33

尽管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”行以大大扩展涵盖格式更改的次数。


3
我想补充"yyyyMMdd"的在formats阵列的准确性降低到天,因为这是有时当一个RFC 5545 RRULE将依靠DTSTART提供时间的情况下。
Kyle Falconer 2014年

1
使用K使您可以将不同的时区处理放在一起。我在stackoverflow.com/a/31246449/400547上有一个更广泛的变体,但是它是否太宽泛(接受有效的ISO 8601但未在更常见的配置文件中使用的东西),但确实显示了如何K通过第三。
乔恩·汉娜

20
using System.Globalization;

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

1
在LinqPad中产生False和d ~~>“ 1/1/0001 12:00:00 AM” :(
Reb.Cabin

@Reb:“ 2010-08-20T15:00:00”和“ s”,如果最后没有“ Z”
abatishchev 2011年

更正了:) Z出现在我所有的样本中(碰巧来自各种GPS装置和GPX文件)
Reb.Cabin 2011年

在另一个ISO 8601参考文献中发现,“ Z”代表时区-与时区相同。
Reb.Cabin

30
Z实际上代表Zulu时间或UTC。en.wikipedia.org/wiki/ISO_8601#UTC
Peter Stephens

19

这是一个对我更好的软件(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格式。谢谢!
anthv123

1
为什么这返回的时间戳不是UTC ?!由于“ DST在全球范围内差异如此之大”,因此不应将“不变文化”与“ AssumeUniversal”一起使用,这大大违反了“最小惊讶原则”,因此,如果您开始运行代码,则在本地流行的时区返回可能会引入错误在具有不同设置的服务器上!
Elaskanator

7

完全匹配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,这取决于您的时间在哪个区域。


1
这对我有用,但我还必须更改AssumeUniversalAdjustToUniversal
奥古斯托·巴雷托

4

在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"));

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.