Cách tạo .NET DateTime từ định dạng ISO 8601


130

Tôi đã tìm thấy cách biến DateTime thành định dạng ISO 8601 , nhưng không có cách nào để làm ngược lại trong C #.

Tôi có 2010-08-20T15:00:00Z, và tôi muốn biến nó thành một DateTimevật thể.

Tôi có thể tự tách các phần của chuỗi, nhưng có vẻ như rất nhiều công việc cho một cái gì đó đã là một tiêu chuẩn quốc tế.


1
bản sao có thể của Convert String to Date in .NET
abatishchev

1
@Aidin: 24 tháng 8, 10 lúc 12:02
abatishchev

@Aidin: và vâng, đây là một bản sao. Sự khác biệt duy nhất trong định dạng. Phần còn lại là như nhau.
abatishchev

6
@abatishchev, và đó là lý do tại sao nó không phải là bản sao. Câu trả lời trong "lặp lại" không xử lý 8601.
spiralis

3
Vâng, đây không phải là một bản sao. Câu hỏi này là cụ thể để phân tích định dạng ISO 8601.
Jose

Câu trả lời:


142

Giải pháp này sử dụng phép liệt kê DateTimeStyles và nó cũng hoạt động với Z.

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

Điều này in giải pháp hoàn hảo.


3
Các giải pháp chỉnh sửa DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);dường như làm việc độc đáo.
j3ko

4
Bất cứ ai cũng muốn giải thích về DateTimeStyles.RoundtripKind? mô tả MSDN này là trống.
Giáo xứ Steve

8
Có vẻ như câu hỏi này đã được chỉnh sửa để phản ánh một câu trả lời tốt hơn nhưng vì @MamtaD ghi đè lên câu trả lời ban đầu, các bình luận trở nên rất sai lệch. Lúc đầu, tôi không chắc chắn rằng câu trả lời là đúng do các bình luận trên đầu nhưng sau đó tôi nhận ra rằng câu trả lời không chính xác đã được thay thế bằng câu trả lời đúng
Aidin

5
Không làm việc cho tôi với các chữ số phân số. 2018-06-19T14:56:14.123Zđược phân tích cú pháp theo giờ địa phương, không phải UTC. Tôi sử dụng CultureInfo.InvariantCulturethay vì null.
Erik Hart

1
Để biết thêm thông tin về DateTimeStyles.RoundTripKind, hãy xem stackoverflow.com/q/39572395/2014893
Robert K. Bell

33

Mặc dù MSDN nói rằng các định dạng "s" và "o" phản ánh tiêu chuẩn, nhưng dường như chúng chỉ có thể phân tích một tập hợp con giới hạn của nó. Đặc biệt nó là một vấn đề nếu chuỗi chứa đặc tả múi giờ. (Không áp dụng cho các định dạng ISO8601 cơ bản hoặc giảm các định dạng chính xác - tuy nhiên đây không phải là trường hợp chính xác của bạn.) Đó là lý do tại sao tôi sử dụng các chuỗi định dạng tùy chỉnh khi phân tích cú pháp ISO8601. Hiện tại đoạn trích ưa thích của tôi là:

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

Nếu bạn không nhớ phân tích các chuỗi không có TZ (tôi làm), bạn có thể thêm một dòng "s" để mở rộng đáng kể số lượng thay đổi định dạng được bảo hiểm.


3
Tôi sẽ thêm "yyyyMMdd"vào formatsmảng cho độ chính xác giảm xuống còn vài ngày, vì đôi khi đây là trường hợp khi RFC 5545 RRULE sẽ dựa vào DTSTART để cung cấp thời gian.
Kyle Falconer

1
Sử dụng Kcho phép bạn cuộn các tay cầm múi giờ khác nhau của bạn với nhau. Tôi có một biến thể mở rộng hơn tại stackoverflow.com/a/31246449/400547 nhưng nếu nó quá rộng rãi (chấp nhận công cụ ISO 8601 hợp lệ nhưng không được sử dụng trong các cấu hình phổ biến hơn) nhưng nó cho thấy cách Kgiảm kích thước bằng cách ngày thứ ba.
Jon Hanna

20
using System.Globalization;

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

1
tạo Sai và d ~ ~> "1/1/0001 12:00:00 AM" trong LinqPad :(
Reb.Cabin

@Reb: "2010-08-20T15: 00: 00" và "s", nếu không có "Z" ở cuối
abatishchev

đã sửa :) Z xuất hiện trong tất cả các mẫu của tôi (xuất hiện từ nhiều đơn vị GPS và tệp GPX khác nhau)
Reb.Cabin

đã tìm ra trong một tham chiếu ISO 8601 khác rằng "Z" là viết tắt của Vùng - như trong Múi giờ.
Reb.Cabin

30
Z thực sự là viết tắt của thời gian Zulu hoặc UTC. vi.wikipedia.org/wiki/ISO_8601#UTC
Peter Stephens

19

Đây là một hoạt động tốt hơn đối với tôi ( phiên bản 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()

sản xuất

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

Hiện đang sử dụng điều này để xác minh trong các bài kiểm tra đơn vị của tôi rằng tất cả các chuỗi tôi dự kiến ​​là ngày có định dạng Iso8601. Cảm ơn!
anthv123

1
Tại sao điều này trả lại dấu thời gian không có trong UTC?! Khá vi phạm Nguyên tắc tối thiểu gây ngạc nhiên vì "Văn hóa bất biến" với "AssumeUniversal" không nên làm điều này vì DST khác biệt rất lớn trên toàn thế giới, do đó, việc quay lại múi giờ thịnh hành tại địa phương của bạn có thể gây ra lỗi nếu bạn bắt đầu chạy mã trên một máy chủ với các cài đặt khác nhau!
Elaskanator

7

Điều quan trọng là phải khớp chính xác định dạng của chuỗi ISO TryParseExactđể hoạt động. Tôi đoán Chính xác là Chính xác và câu trả lời này là rõ ràng đối với hầu hết nhưng dù sao ...

Trong trường hợp của tôi, câu trả lời của Reb.Cabin không hoạt động vì tôi có đầu vào hơi khác theo "giá trị" bên dưới.

Giá trị: 2012-08-10T14:00:00.000Z

Có một số 000 trong đó trong một phần nghìn giây và có thể có nhiều hơn nữa.

Tuy nhiên nếu tôi thêm một số .fffđịnh dạng như hình dưới đây, tất cả đều ổn.

Chuỗi định dạng: @"yyyy-MM-dd\THH:mm:ss.fff\Z"

Trong cửa sổ ngay lập tức VS2010:

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

thật

Bạn có thể phải sử dụng DateTimeStyles.AssumeLocaltùy thuộc vào khu vực thời gian của bạn dành cho ...


1
Điều này làm việc cho tôi, nhưng tôi cũng phải thay đổi AssumeUniversalđể AdjustToUniversal.
Augusto Barreto

4

Điều này hoạt động tốt trong 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"));

-1

DateTime.ParseExact(...) cho phép bạn nói cho trình phân tích cú pháp những gì mỗi nhân vật đại diện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.