Как создать .NET DateTime из формата ISO 8601


130

Я нашел, как преобразовать DateTime в формат ISO 8601 , но не знаю, как сделать обратное в C #.

У меня есть 2010-08-20T15:00:00Z, и я хочу превратить это в DateTimeобъект.

Я мог бы сам разделить части струны, но это кажется большим трудом для того, что уже является международным стандартом.


1
возможный дубликат Convert String to Date в .NET
Абатищев

1
@Aidin: 24 авг., 12:02
Абатищев,

@Aidin: и да, это дубликат. Единственная разница в формате. В остальном то же самое.
Абатищев

6
@abatishchev, а потому и не дубликат. Ответ в «дубликате» не
касается

3
Да это не дубликат. Этот вопрос относится к разбору формата ISO 8601.
Хосе

Ответы:


143

Это решение использует перечисление 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

4
Любой желающий уточнить это DateTimeStyles.RoundtripKind? описание MSDN пусто.
Стив Пэриш

8
кажется, этот вопрос был отредактирован, чтобы отразить лучший ответ, но поскольку @MamtaD перезаписал исходный ответ, комментарии становятся очень вводящими в заблуждение. Вначале я не был уверен, что ответ правильный из-за комментариев вверху, но затем я понял, что неправильный ответ был позже заменен правильным
Айдин

5
У меня не работает с дробными цифрами. 2018-06-19T14:56:14.123Zанализируется как местное время, а не UTC. Я использую CultureInfo.InvariantCultureвместо null.
Эрик Харт

1
Для получения дополнительной информации DateTimeStyles.RoundTripKindсм. Stackoverflow.com/q/39572395/2014893
Роберт К. Белл

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 для предоставления времени.
Кайл Фалконер

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
выдает False и d ~~> "1/1/0001 12:00:00 AM" в LinqPad :(
Reb.Cabin

@Reb: «2010-08-20T15: 00: 00» и «s», если в конце нет «Z»
Абатищев

исправлено :) Z появляется во всех моих сэмплах (которые происходят из различных устройств GPS и файлов GPX)
Reb.Cabin

обнаружил в другой ссылке ISO 8601, что «Z» означает зону - как в часовом поясе.
Reb.Cabin

30
Z на самом деле означает зулусское время или UTC. en.wikipedia.org/wiki/ISO_8601#UTC
Питер Стивенс,

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 ?! Довольно серьезное нарушение принципа наименьшего удивления, поскольку «инвариантная культура» с «AssumeUniversal» не должна этого делать, потому что летнее время сильно различается во всем мире, поэтому возвращение в местный преобладающий часовой пояс может привести к ошибкам, если вы начнете запускать код. на сервере с разными настройками!
Elaskanator

7

Кажется важным точно соответствовать формату строки ISO для TryParseExactработы. Я думаю, что Exact is 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
Это сработало для меня, но мне также пришлось перейти AssumeUniversalна AdjustToUniversal.
Аугусто Баррето,

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.