So erstellen Sie eine .NET DateTime im ISO 8601-Format

130

Ich habe herausgefunden, wie man eine DateTime in ein ISO 8601- Format umwandelt, aber nichts darüber, wie man in C # das Gegenteil macht.

Ich habe 2010-08-20T15:00:00Zund ich möchte es in ein DateTimeObjekt verwandeln .

Ich könnte die Teile der Saite selbst trennen, aber das scheint eine Menge Arbeit für etwas zu sein, das bereits ein internationaler Standard ist.

Ripter
quelle
1
Mögliches Duplikat von String in Datum konvertieren in .NET
abatishchev
1
@Aidin: 24. August 10 um 12:02
Uhr
@Aidin: und ja, das ist ein Duplikat. Der einzige Unterschied im Format. Der Rest ist der gleiche.
Abatishchev
6
@abatishchev, und deshalb ist es kein Duplikat. Die Antwort im "Duplikat" behandelt 8601 nicht.
Spiralis
3
Ja, dies ist kein Duplikat. Diese Frage bezieht sich speziell auf das Parsen des ISO 8601-Formats.
Jose

Antworten:

142

Diese Lösung verwendet die DateTimeStyles- Enumeration und funktioniert auch mit Z.

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

Dies druckt die Lösung perfekt.

Mamta D.
quelle
3
Die bearbeitete Lösung von DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);scheint gut zu funktionieren.
j3ko
4
Jeder, der diese DateTimeStyles.RoundtripKind? MSDN-Beschreibung näher erläutern möchte, ist leer.
Steve Parish
8
Es scheint, dass diese Frage bearbeitet wurde, um eine bessere Antwort wiederzugeben, aber da @MamtaD die ursprüngliche Antwort überschrieben hat, werden die Kommentare sehr irreführend. Am Anfang war ich mir nicht sicher, ob die Antwort aufgrund der obigen Kommentare richtig ist, aber dann wurde mir klar, dass die falsche Antwort durch die richtige ersetzt wurde
Aidin
5
Funktioniert bei mir nicht mit gebrochenen Ziffern. 2018-06-19T14:56:14.123Zwird als Ortszeit analysiert, nicht als UTC. Ich benutze CultureInfo.InvariantCultureanstelle von null.
Erik Hart
1
Weitere Informationen DateTimeStyles.RoundTripKindfinden Sie unter stackoverflow.com/q/39572395/2014893
Robert K. Bell
33

Obwohl MSDN sagt, dass die Formate "s" und "o" den Standard widerspiegeln, scheinen sie nur eine begrenzte Teilmenge davon analysieren zu können. Insbesondere ist es ein Problem, wenn die Zeichenfolge eine Zeitzonenspezifikation enthält. (Weder für grundlegende ISO8601-Formate noch für Formate mit reduzierter Genauigkeit - dies ist jedoch nicht genau Ihr Fall.) Aus diesem Grund verwende ich beim Parsen von ISO8601 benutzerdefinierte Formatzeichenfolgen. Derzeit ist mein bevorzugter Ausschnitt:

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

Wenn es Ihnen nichts ausmacht, TZ-freie Zeichenfolgen zu analysieren (ich auch), können Sie eine "s" -Zeile hinzufügen, um die Anzahl der abgedeckten Formatänderungen erheblich zu erhöhen.

Alexey Biryukov
quelle
3
Ich würde "yyyyMMdd"das formatsArray hinzufügen, um die Genauigkeit auf Tage zu reduzieren, da dies manchmal der Fall ist, wenn eine RFC 5545-RRULE auf einen DTSTART angewiesen ist, um die Zeit bereitzustellen.
Kyle Falconer
1
Mit Kkönnen Sie Ihre verschiedenen Zeitzonen-Handlings zusammenrollen. Ich habe eine umfangreichere Variante unter stackoverflow.com/a/31246449/400547, aber es ist, wenn etwas zu umfangreich ist (akzeptiert Dinge, die nach ISO 8601 gültig sind, aber in den gängigeren Profilen nicht verwendet werden), aber es zeigt, wie Kdie Größe um a reduziert werden kann dritte.
Jon Hanna
20
using System.Globalization;

DateTime d;
DateTime.TryParseExact(
    "2010-08-20T15:00:00",
    "s",
    CultureInfo.InvariantCulture,
    DateTimeStyles.AssumeUniversal, out d);
abatishchev
quelle
1
produziert False und d ~~> "1/1/0001 12:00:00 AM" in LinqPad :(
Reb.Cabin
@Reb: "2010-08-20T15: 00: 00" und "s", wenn kein "Z" am Ende
abatishchev
korrigiert :) Das Z taucht in allen meinen Beispielen auf (die zufällig von verschiedenen GPS-Geräten und GPX-Dateien stammen)
Reb.Cabin
In einer anderen ISO 8601-Referenz wurde festgestellt, dass das "Z" für Zone steht - wie in der Zeitzone.
Reb.Cabin
30
Z steht eigentlich für Zulu Time oder UTC. en.wikipedia.org/wiki/ISO_8601#UTC
Peter Stephens
19

Hier ist eine, die für mich besser funktioniert ( LINQPad- Version):

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

produziert

true
8/20/2010 8:00:00 AM
Reb.Cabin
quelle
Derzeit wird dies verwendet, um in meinen Komponententests zu überprüfen, ob alle Zeichenfolgen, die ich als Datumsangaben erwarte, das Iso8601-Format haben. Vielen Dank!
Anthv123
1
Warum gibt dies einen Zeitstempel zurück, der nicht in UTC ist?! Ein ziemlich großer Verstoß gegen das Prinzip des geringsten Erstaunens, da "Invariant Culture" mit "AssumeUniversal" dies nicht tun sollte, da sich die Sommerzeit auf der ganzen Welt so stark unterscheidet. Wenn Sie also in Ihre lokale Zeitzone zurückkehren, kann dies zu Fehlern führen, wenn Sie den Code ausführen auf einem Server mit unterschiedlichen Einstellungen!
Elaskanator
7

Es scheint wichtig zu sein, das Format der ISO-Zeichenfolge genau anzupassen, damit TryParseExactes funktioniert. Ich denke, genau ist genau und diese Antwort ist für die meisten offensichtlich, aber trotzdem ...

In meinem Fall funktioniert die Antwort von Reb.Cabin nicht, da ich eine etwas andere Eingabe habe als mein "Wert" unten.

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

Es gibt einige zusätzliche 000 für Millisekunden und es kann mehr geben.

Wenn ich jedoch einige .fffwie unten gezeigt zum Format hinzufüge , ist alles in Ordnung.

Format String: @"yyyy-MM-dd\THH:mm:ss.fff\Z"

Im VS2010-Sofortfenster:

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

wahr

Sie müssen möglicherweise auch verwenden, DateTimeStyles.AssumeLocalje nachdem, für welche Zone Ihre Zeit ist ...

Rob Von Nesselrode
quelle
1
Das ist für mich gearbeitet, aber ich auch ändern musste AssumeUniversalzu AdjustToUniversal.
Augusto Barreto
4

Dies funktioniert gut in 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"));
Zar Shardan
quelle
-1

DateTime.ParseExact(...) Mit dieser Option können Sie dem Parser mitteilen, was jedes Zeichen darstellt.

Jerod Houghtelling
quelle