Cara membuat .NET DateTime dari format ISO 8601

130

Saya telah menemukan cara mengubah DateTime menjadi format ISO 8601 , tetapi tidak ada cara melakukan kebalikannya di C #.

Saya punya 2010-08-20T15:00:00Z, dan saya ingin mengubahnya menjadi DateTimeobjek.

Saya bisa memisahkan bagian-bagian dari senar itu sendiri, tetapi sepertinya banyak pekerjaan untuk sesuatu yang sudah menjadi standar internasional.

Ripter
sumber
1
kemungkinan duplikat dari String Konversi ke Tanggal dalam .NET
abatishchev
1
@Aidin: 24 Agustus '10 jam 12:02
abatishchev
@Aidin: dan ya, ini duplikat. Satu-satunya perbedaan dalam format. Sisanya sama.
abatishchev
6
@abatishchev, dan itulah mengapa itu bukan duplikat. Jawaban dalam "duplikat" tidak menangani 8601.
Spiralis
3
Ya ini bukan duplikat. Pertanyaan ini khusus untuk mem-parsing format ISO 8601.
Jose

Jawaban:

142

Solusi ini menggunakan enumerasi DateTimeStyles , dan juga bekerja dengan Z.

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

Ini mencetak solusinya dengan sempurna.

Mamta D
sumber
3
Solusi yang telah diedit DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);tampaknya bekerja dengan baik.
j3ko
4
Siapa pun yang ingin menguraikan DateTimeStyles.RoundtripKind? deskripsi MSDN ini kosong.
Steve Parish
8
tampaknya pertanyaan ini diedit untuk mencerminkan jawaban yang lebih baik tetapi karena @MamtaD menimpa jawaban asli, komentarnya menjadi sangat menyesatkan. Pada awalnya saya tidak yakin bahwa jawabannya benar karena komentar di atas tetapi kemudian saya menyadari bahwa jawaban yang salah kemudian diganti dengan yang benar
Aidin
5
Tidak bekerja untuk saya dengan angka pecahan. 2018-06-19T14:56:14.123Zdiuraikan sebagai waktu lokal, bukan UTC. Saya menggunakan CultureInfo.InvariantCulturebukan null.
Erik Hart
1
Untuk info lebih lanjut tentang DateTimeStyles.RoundTripKind, lihat stackoverflow.com/q/39572395/2014893
Robert K. Bell
33

Meskipun MSDN mengatakan bahwa format "s" dan "o" mencerminkan standar, mereka tampaknya hanya dapat menguraikan sebagian saja. Terutama masalah jika string berisi spesifikasi zona waktu. (Baik itu berlaku untuk format ISO8601 dasar, atau format presisi yang diperkecil - namun ini bukan kasus Anda.) Itulah mengapa saya menggunakan string format khusus ketika harus mem-parsing ISO8601. Saat ini cuplikan pilihan saya adalah:

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

Jika Anda tidak keberatan mem-parsing string TZ-less (saya lakukan), Anda dapat menambahkan baris "s" untuk menambah jumlah perubahan format yang dibahas.

Alexey Biryukov
sumber
3
Saya akan menambahkan "yyyyMMdd"dalam formatsarray untuk akurasi dikurangi menjadi hari, karena ini adalah kadang-kadang terjadi ketika sebuah RFC 5545 RRULE akan bergantung pada DTSTART untuk memberikan waktu.
Kyle Falconer
1
Menggunakan Kmemungkinkan Anda untuk menggabungkan penanganan zona waktu yang berbeda. Saya memiliki varian yang lebih luas di stackoverflow.com/a/31246449/400547 tetapi itu jika ada sesuatu yang terlalu luas (menerima hal-hal yang valid ISO 8601 tetapi tidak digunakan dalam profil yang lebih umum) tetapi itu menunjukkan bagaimana cara Kmengurangi ukuran dengan ketiga.
Jon Hanna
20
using System.Globalization;

DateTime d;
DateTime.TryParseExact(
    "2010-08-20T15:00:00",
    "s",
    CultureInfo.InvariantCulture,
    DateTimeStyles.AssumeUniversal, out d);
abatishchev
sumber
1
menghasilkan False dan d ~~> "1/1/0001 12:00:00 AM" di LinqPad :(
Reb.Cabin
@Reb: "2010-08-20T15: 00: 00" dan "s", jika tidak ada "Z" di akhir
abatishchev
dikoreksi :) Z muncul di semua sampel saya (yang kebetulan berasal dari berbagai unit GPS dan file GPX)
Reb.Cabin
ditemukan dalam referensi ISO 8601 lain bahwa "Z" adalah singkatan dari Zone - seperti dalam Time Zone.
Reb.Cabin
30
Z sebenarnya adalah singkatan dari Zulu time atau UTC. en.wikipedia.org/wiki/ISO_8601#UTC
Peter Stephens
19

Ini adalah salah satu yang bekerja lebih baik untuk saya ( versi 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()

menghasilkan

true
8/20/2010 8:00:00 AM
Reb.Cabin
sumber
Saat ini menggunakan ini untuk memverifikasi dalam pengujian unit saya bahwa semua string yang saya harapkan tanggal adalah format Iso8601. Terima kasih!
anthv123
1
Mengapa ini mengembalikan stempel waktu bukan di UTC ?! Cukup banyak pelanggaran terhadap Prinsip Least Astonancy karena "budaya Invarian" dengan "AssumeUniversal" tidak boleh melakukan hal ini karena DST berbeda sangat liar di seluruh dunia, jadi kembali di zona waktu setempat Anda mungkin menimbulkan bug jika Anda mulai menjalankan kode di server dengan pengaturan berbeda!
Elaskanator
7

Tampaknya penting untuk mencocokkan dengan tepat format string ISO TryParseExactagar berfungsi. Saya kira Exact adalah Exact dan jawaban ini jelas bagi sebagian besar tetapi tetap ...

Dalam kasus saya, jawaban Reb.Cabin tidak berfungsi karena saya memiliki input yang sedikit berbeda sesuai "nilai" saya di bawah.

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

Ada beberapa 000 tambahan di sana selama milidetik dan mungkin ada lebih banyak.

Namun jika saya menambahkan beberapa .fffke format seperti yang ditunjukkan di bawah ini, semuanya baik-baik saja.

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

Di Jendela Segera VS2010:

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

benar

Anda mungkin harus menggunakan DateTimeStyles.AssumeLocaljuga tergantung pada zona waktu Anda untuk ...

Rob Von Nesselrode
sumber
1
Ini bekerja untuk saya, tapi saya juga harus berubah AssumeUniversalke AdjustToUniversal.
Augusto Barreto
4

Ini berfungsi dengan baik di 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
sumber
-1

DateTime.ParseExact(...) memungkinkan Anda memberi tahu parser apa yang diwakili masing-masing karakter.

Jerod Houghtelling
sumber