Як створити .NET DateTime у форматі ISO 8601


130

Я з’ясував, як перетворити DateTime у формат ISO 8601 , але нічого в тому, як зробити реверс у C #.

У мене є 2010-08-20T15:00:00Z, і я хочу перетворити його на DateTimeоб’єкт.

Я міг би самостійно відокремити частини струни, але це здається великою роботою для чогось, що вже є міжнародним стандартом.


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

1
@Aidin: 24 серпня '10 о 12:02
абатищев

@Aidin: і так, це дублікат. Єдина різниця у форматі. Решта ж.
абатищев

6
@abatishchev, і тому це не дублікат. Відповідь у "дублікаті" не стосується 8601.
Спіраліс

3
Так, це не дублікат. Це питання стосується розбору формату ISO 8601.
Хосе

Відповіді:


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

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" у LinqPad :(
Reb.Cabin

@Reb: "2010-08-20T15: 00: 00" і "s", якщо в кінці немає "Z"
абатищев

виправлено :) Z відображається у всіх моїх зразках (які трапляються з різних GPS-пристроїв та файлів GPX)
Reb.Cabin

в іншому посиланні ISO 8601 з'ясувалося, що "Z" означає Zone - як у Time Zone.
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" не повинна цього робити, оскільки DST так дико відрізняється по всьому світу, тому повернення в локальний переважаючий часовий пояс може ввести помилки, якщо ви почнете виконувати код на сервері з різними налаштуваннями!
Еласканатор

7

Здається, важливо точно відповідати формату рядка ISO для TryParseExact роботи. Я здогадуюсь Точне точно, і ця відповідь для більшості очевидна, але все одно ...

У моєму випадку відповідь Reb.Cabin не працює, оскільки я маю дещо інший внесок відповідно до мого "значення" нижче.

Значення: 2012-08-10T14:00:00.000Z

Є кілька зайвих тисяч там протягом мілісекунд, а може бути і більше.

Однак якщо я додаю трохи .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.