Jak utworzyć .NET DateTime z formatu ISO 8601


135

Dowiedziałem się, jak zamienić DateTime na format ISO 8601 , ale nie ma nic o tym, jak zrobić odwrotność w C #.

Mam 2010-08-20T15:00:00Zi chcę przekształcić go w DateTimeprzedmiot.

Mógłbym sam oddzielić części struny, ale wydaje się, że to dużo pracy jak na coś, co jest już międzynarodowym standardem.



1
@Aidin: 24 sierpnia 10 o 12:02
abatishchev

@Aidin: i tak, to jest duplikat. Jedyna różnica w formacie. Reszta jest taka sama.
abatishchev

6
@abatishchev i dlatego nie jest duplikatem. Odpowiedź w „duplikat” nie obsługuje 8601.
spiralis

3
Tak, to nie jest duplikat. To pytanie jest specyficzne dla analizowania formatu ISO 8601.
Jose

Odpowiedzi:


149

To rozwiązanie korzysta z wyliczenia DateTimeStyles i działa również z Z.

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

To doskonale drukuje rozwiązanie.


3
Edytowane rozwiązanie DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);wydaje się działać ładnie.
j3ko,

4
Każdy, kto chce rozwinąć ten DateTimeStyles.RoundtripKind? opis MSDN, jest pusty.
Steve Parish

8
wydaje się, że to pytanie zostało zredagowane, aby odzwierciedlić lepszą odpowiedź, ale ponieważ @MamtaD nadpisał oryginalną odpowiedź, komentarze stają się bardzo mylące. Na początku nie byłem pewien, czy odpowiedź jest poprawna ze względu na komentarze u góry, ale potem zdałem sobie sprawę, że błędna odpowiedź została zastąpiona poprawną
Aidin

5
Nie działa dla mnie z cyframi ułamkowymi. 2018-06-19T14:56:14.123Zjest analizowany jako czas lokalny, a nie UTC. Używam CultureInfo.InvariantCulturezamiast null.
Erik Hart

1
Aby uzyskać więcej informacji DateTimeStyles.RoundTripKind, zobacz stackoverflow.com/q/39572395/2014893
Robert K. Bell

35

Chociaż MSDN mówi, że formaty „s” i „o” odzwierciedlają standard, wydaje się, że są w stanie przeanalizować tylko ograniczony podzbiór. Szczególnie jest to problem, jeśli ciąg zawiera specyfikację strefy czasowej. (Ani dla podstawowych formatów ISO8601, ani dla formatów o zmniejszonej precyzji - jednak nie jest to dokładnie w twoim przypadku). Dlatego używam niestandardowych ciągów formatów, jeśli chodzi o parsowanie ISO8601. Obecnie mój preferowany fragment to:

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

Jeśli nie masz nic przeciwko analizowaniu ciągów bez TZ (tak robię), możesz dodać wiersz „s”, aby znacznie zwiększyć liczbę objętych zmian formatu.


3
Dodałbym "yyyyMMdd"w formatstablicy, aby dokładność została zredukowana do dni, ponieważ czasami ma to miejsce, gdy RRULE RFC 5545 będzie polegać na DTSTART, aby zapewnić czas.
Kyle Falconer

1
Użycie Kumożliwia jednoczesne łączenie obsługi różnych stref czasowych. Mam bardziej rozbudowany wariant na stackoverflow.com/a/31246449/400547, ale jest on zbyt obszerny (akceptuje rzeczy, które są zgodne z ISO 8601, ale nie są używane w bardziej popularnych profilach), ale pokazuje, jak Kmożna zmniejszyć rozmiar o trzeci.
Jon Hanna

21
using System.Globalization;

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

1
generuje False id ~~> "1/1/0001 12:00:00 AM" w LinqPad :(
Reb.Cabin

@Reb: „2010-08-20T15: 00: 00” i „s”, jeśli na końcu nie ma „Z”
abatishchev

poprawione :) Z pojawia się we wszystkich moich próbkach (które zdarzają się pochodzić z różnych urządzeń GPS i plików GPX)
Reb.Cabin

dowiedziałem się w innym dokumencie ISO 8601, że „Z” oznacza strefę - jak w strefie czasowej.
Reb

31
Z faktycznie oznacza czas Zulu lub UTC. en.wikipedia.org/wiki/ISO_8601#UTC
Peter Stephens

19

Oto taki, który działa lepiej dla mnie ( wersja 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()

produkuje

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

Obecnie używam tego do sprawdzenia w moich testach jednostkowych, że wszystkie ciągi, których oczekuję, że będą datami, mają format Iso8601. Dzięki!
anthv123

1
Dlaczego to zwraca sygnaturę czasową inną niż UTC ?! Dość duże naruszenie zasady najmniejszego zdumienia, ponieważ „Niezmienna kultura” z „AssumeUniversal” nie powinna tego robić, ponieważ czas letni różni się tak bardzo na całym świecie, więc powrót do lokalnej strefy czasowej może spowodować błędy, jeśli zaczniesz uruchamiać kod na serwerze z różnymi ustawieniami!
Elaskanator

7

Wydaje się ważne, aby dokładnie dopasować format ciągu ISO TryParseExactdo pracy. Myślę, że Exact to Exact i ta odpowiedź jest oczywista dla większości, ale w każdym razie ...

W moim przypadku odpowiedź Reb.Cabin nie działa, ponieważ mam nieco inne dane wejściowe, jak na moją „wartość” poniżej.

Wartość: 2012-08-10T14:00:00.000Z

Jest tam kilka dodatkowych tysięcy na milisekundy, a może być ich więcej.

Jeśli jednak dodam trochę .fffdo formatu, jak pokazano poniżej, wszystko jest w porządku.

Ciąg formatu: @"yyyy-MM-dd\THH:mm:ss.fff\Z"

W oknie bezpośrednim VS2010:

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

prawdziwe

Być może będziesz musiał użyć, DateTimeStyles.AssumeLocalw zależności od strefy, dla której jest twój czas ...


1
Ten pracował dla mnie, ale ja też musiałem zmienić AssumeUniversalna AdjustToUniversal.
Augusto Barreto

4

Działa to dobrze w 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"));

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.