Come creare un DateTime .NET dal formato ISO 8601


130

Ho trovato come trasformare un DateTime in un formato ISO 8601 , ma nulla su come fare il contrario in C #.

Ho 2010-08-20T15:00:00Z, e voglio trasformarlo in un DateTimeoggetto.

Potrei separare le parti della stringa da solo, ma sembra un sacco di lavoro per qualcosa che è già uno standard internazionale.


1

1
@Aidin: 24 agosto 10 alle 12:02
abatishchev

@Aidin: e sì, questo è un duplicato. L'unica differenza di formato. Il riposo è lo stesso.
abatishchev,

6
@abatishchev, ed è per questo che non è un duplicato. La risposta nel "duplicato" non gestisce 8601.
Spiralis,

3
Sì, questo non è un duplicato. Questa domanda è specifica per l'analisi del formato ISO 8601.
Jose,

Risposte:


142

Questa soluzione utilizza l' enumerazione DateTimeStyles e funziona anche con Z.

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

Questo stampa la soluzione perfettamente.


3
La soluzione modificata di DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);sembra funzionare bene.
j3ko,

4
Chiunque desideri approfondire questa DateTimeStyles.RoundtripKind? descrizione MSDN è vuoto.
Steve Parish,

8
sembra che questa domanda sia stata modificata per riflettere una risposta migliore ma poiché @MamtaD ha sovrascritto la risposta originale, i commenti diventano molto fuorvianti. All'inizio non ero sicuro che la risposta fosse corretta a causa dei commenti in alto, ma poi mi sono reso conto che quest'ultima risposta è stata sostituita con una corretta
Aidin

5
Non funziona per me con cifre frazionarie. 2018-06-19T14:56:14.123Zviene analizzato come ora locale, non UTC. Io uso CultureInfo.InvariantCultureinvece di null.
Erik Hart,

1
Per ulteriori informazioni DateTimeStyles.RoundTripKind, vedere stackoverflow.com/q/39572395/2014893
Robert K. Bell,

33

Sebbene MSDN affermi che i formati "s" e "o" riflettono lo standard, sembrano essere in grado di analizzarne solo un sottoinsieme limitato. Soprattutto è un problema se la stringa contiene la specifica del fuso orario. (Né per i formati ISO8601 di base, né per i formati di precisione ridotta, tuttavia non è esattamente questo il caso.) Ecco perché utilizzo analisi di stringhe di formato personalizzate per analizzare ISO8601. Attualmente il mio frammento preferito è:

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

Se non ti dispiace analizzare le stringhe senza TZ (lo so), puoi aggiungere una linea "s" per estendere notevolmente il numero di alterazioni del formato coperto.


3
Aggiungerei "yyyyMMdd"l' formatsarray per una precisione ridotta a giorni, poiché a volte questo è il caso in cui un RRCLE RFC 5545 farà affidamento su un DTSTART per fornire il tempo.
Kyle Falconer,

1
L'utilizzo Kconsente di raggruppare le diverse gestioni dei fusi orari. Ho una variante più ampia su stackoverflow.com/a/31246449/400547 ma è qualcosa di troppo esteso (accetta elementi validi ISO 8601 ma non utilizzati nei profili più comuni) ma mostra come Kridurre le dimensioni di un terzo.
Jon Hanna,

20
using System.Globalization;

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

1
produce False e d ~~> "1/1/0001 12:00:00 AM" in LinqPad :(
Reb.Cabin

@Reb: "2010-08-20T15: 00: 00" e "s", se non c'è "Z" alla fine
abatishchev

corretto :) la Z appare in tutti i miei campioni (che provengono da varie unità GPS e file GPX)
Reb.Cabin

scoperto in un altro riferimento ISO 8601 che la "Z" sta per Zona - come in Fuso orario.
Reb.Cabin

30
Z in realtà sta per ora Zulu o UTC. en.wikipedia.org/wiki/ISO_8601#UTC
Peter Stephens,

19

Eccone uno che funziona meglio per me ( versione 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()

produce

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

Attualmente sto usando questo per verificare nei test delle mie unità che tutte le stringhe che mi aspetto siano date sono in formato Iso8601. Grazie!
anthv123,

1
Perché questo restituisce un timestamp non in UTC ?! Piuttosto una grande violazione del principio del minimo stupore poiché "Cultura invariante" con "AssumeUniversal" non dovrebbe fare questo perché l'ora legale differisce così selvaggiamente in tutto il mondo, quindi il ritorno nel tuo fuso orario prevalente locale potrebbe introdurre bug se inizi a eseguire il codice su un server con impostazioni diverse!
Elaskanator,

7

Sembra importante abbinare esattamente il formato della stringa ISO per TryParseExactfunzionare. Immagino che Exact sia Exact e questa risposta è ovvia per la maggior parte ma comunque ...

Nel mio caso, la risposta di Reb.Cabin non funziona in quanto ho un input leggermente diverso in base al mio "valore" di seguito.

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

Ci sono alcuni 000 in più per millisecondi e potrebbero essercene di più.

Tuttavia, se ne aggiungo un po ' .fffal formato come mostrato di seguito, va tutto bene.

Stringa formato: @"yyyy-MM-dd\THH:mm:ss.fff\Z"

Nella finestra immediata di VS2010:

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

vero

Potrebbe essere necessario utilizzare DateTimeStyles.AssumeLocalanche a seconda di quale zona è il tuo tempo per ...


1
Questo ha funzionato per me, ma ho anche dovuto cambiare AssumeUniversala AdjustToUniversal.
Augusto Barreto,

4

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.