2009-07-29 38 views
52

Cách chuyển đổi sang UTC từ công việc định dạng chuẩn DateTime?DateTime.ToUniversalTime() hoạt động như thế nào?

Cụ thể hơn, nếu tôi tạo đối tượng DateTime trong một múi giờ và sau đó chuyển sang múi giờ khác và chạy ToUniversalTime() trên đó, làm cách nào để biết chuyển đổi được thực hiện chính xác và thời gian vẫn được thể hiện chính xác?

Trả lời

62

Không có múi giờ ẩn nào được gắn với đối tượng DateTime. Nếu bạn chạy ToUniversalTime() vào nó, nó sử dụng múi giờ của bối cảnh rằng mã đang chạy trong.

Ví dụ, nếu tôi có thể tạo một DateTime từ kỷ nguyên của 1970/01/01, nó mang lại cho tôi cùng một đối tượng DateTime bất kể tôi đang ở đâu trên thế giới.

Nếu tôi chạy ToUniversalTime() trên đó khi tôi đang chạy mã trong Greenwich, sau đó tôi nhận được cùng một lúc. Nếu tôi làm điều đó trong khi tôi sống ở Vancouver, sau đó tôi nhận được một bù đắp DateTime đối tượng của -8 giờ.

Đây là lý do tại sao điều quan trọng là lưu trữ thông tin liên quan đến thời gian trong cơ sở dữ liệu của bạn dưới dạng thời gian UTC khi bạn cần thực hiện bất kỳ loại chuyển đổi hoặc bản địa hóa ngày nào. Hãy xem xét nếu codebase của bạn đã được chuyển đến một cơ sở máy chủ trong một múi giờ khác;)

Chỉnh sửa: lưu ý từ câu trả lời của Joel - DateTime đối tượng theo mặc định được nhập là DateTimeKind.Local. Nếu bạn phân tích cú pháp một ngày và đặt nó là DateTimeKind.Utc thì ToUniversalTime() sẽ không thực hiện chuyển đổi.

Và đây là một bài viết trên "Best Practices Coding with Date Times" và một bài viết trên Converting DateTimes with .Net.

+1

No. Không quan tâm đến thời gian hiện tại. Nó quan tâm đến múi giờ của hệ thống địa phương. –

+12

Bạn không muốn * luôn * lưu trữ thông tin liên quan đến thời gian trong UTC. Nó hoàn toàn phụ thuộc vào thông tin đó thực sự là gì. Instants trong thời gian thường có thể được đại diện trong UTC, nhưng không phải tất cả mọi thứ là ngay lập tức. Ví dụ, tôi đang trên chuyến tàu 17:18 từ Paddington. Lưu ý là "17:18 Châu Âu/Luân Đôn" thay vì "16:18 UTC" - bởi vì khi đồng hồ quay trở lại, thời gian * cục bộ vẫn giữ nguyên. –

+3

Bạn có thể nói rằng tôi làm việc trên một sản phẩm liên quan đến lịch? ;) –

7

Điều gì @womp said, với việc bổ sung nó kiểm tra thuộc tính Loại ngày giờ để xem liệu nó có thể đã là là ngày UTC hay không.

+0

Điểm tốt. Nếu loại không được đặt rõ ràng, nó giả định một thời gian địa phương, và sau đó gọi ToUniversalTime() đặt loại phổ quát vào ngày mới. – womp

+0

Thật đáng để chỉ ra SQL Server không lưu trữ loại (http://stackoverflow.com/questions/823313/linq-to-sql-datetime-values-are-local-kind-unspecified-how-do-i- make-it-utc) vì vậy nếu bạn lưu trữ một ngày UTC trên một máy chủ Hoa Kỳ, nó sẽ được giả định là địa phương –

2

DateTime.ToUniversalTime loại bỏ chênh lệch múi giờ của múi giờ địa phương để bình thường hóa một DateTime thành UTC. Nếu sau đó bạn sử dụng DateTime.ToLocalTime trên giá trị được chuẩn hóa trong múi giờ khác, chênh lệch múi giờ của múi giờ đó sẽ được thêm vào giá trị được chuẩn hóa để biểu diễn chính xác trong múi giờ đó.

29

Thứ nhất, nó kiểm tra xem Kind của DateTime được biết là UTC chưa. Nếu vậy, nó trả về cùng một giá trị.

Nếu không, nó được giả định là giờ địa phương - đó là cục bộ cho máy tính đang chạy và đặc biệt trong múi giờ mà máy tính đang sử dụng khi một số thuộc tính riêng được khởi chạy lần đầu tiên. Điều đó có nghĩa là nếu bạn thay đổi múi giờ sau ứng dụng của bạn đã được bắt đầu, có nhiều khả năng nó sẽ vẫn sử dụng ứng dụng cũ.

Múi giờ chứa đủ thông tin để chuyển đổi giờ địa phương thành thời gian UTC hoặc ngược lại, mặc dù có những thời điểm không rõ ràng hoặc không hợp lệ. (Có những lúc địa phương xảy ra hai lần, và thời gian địa phương mà không bao giờ xảy ra do tiết kiệm thời gian ban ngày.) Các quy tắc để xử lý những trường hợp được quy định tại the documentation:

Nếu ngày và thời gian giá trị ví dụ là một mơ hồ thời gian, phương pháp này giả định rằng nó là một thời gian tiêu chuẩn.(An thời gian mơ hồ là một trong đó có thể ánh xạ thời gian chuẩn hoặc đến thời gian tiết kiệm ánh sáng ban ngày theo giờ địa phương là ) thời gian từ chênh lệch UTC của múi giờ địa phương thành trả lại UTC. (Một thời gian không hợp lệ là một rằng không tồn tại vì các ứng dụng tiết kiệm ánh sáng ban ngày thời gian quy tắc điều chỉnh.)

Các giá trị trả về sẽ có một Kind của DateTimeKind.Utc, vì vậy nếu bạn gọi ToUniveralTime trên rằng nó đã giành không áp dụng bù đắp một lần nữa. (Đây là một cải tiến lớn trên .NET 1.1!)

Nếu bạn muốn có múi giờ phi địa phương, bạn nên sử dụng TimeZoneInfo được giới thiệu trong .NET 3.5 (có các giải pháp hacky cho các phiên bản cũ hơn, nhưng chúng không hay). Để thể hiện ngay lập tức, bạn nên cân nhắc sử dụng DateTimeOffset được giới thiệu trong .NET 2.0SP1, .NET3.0SP1 và .NET 3.5. Tuy nhiên, điều đó vẫn không có múi giờ thực sự được liên kết với nó - chỉ là một khoản bù trừ từ UTC. Điều đó có nghĩa là bạn không biết thời gian địa phương sẽ là một giờ sau đó, ví dụ - các quy tắc DST có thể khác nhau giữa các múi giờ xảy ra để sử dụng cùng một bù đắp cho tức thời cụ thể đó. TimeZoneInfo được thiết kế để đưa các quy tắc lịch sử và tương lai vào tài khoản, thay vì TimeZone có phần đơn giản.

Về cơ bản, hỗ trợ trong .NET 3.5 tốt hơn rất nhiều so với trước đây, nhưng vẫn để lại một số thứ cần thiết cho số học lịch thích hợp. Bất cứ ai ưa thích porting Joda Time để .NET? ;)

+0

Tại sao không .NET luôn lưu trữ ngày trong UTC và tránh vấn đề hoàn toàn? Hay điều đó đảm bảo một chủ đề khác? – derGral

+2

Bạn không phải lúc nào cũng muốn có thời gian UTC. Các vấn đề ngày/giờ khá phức tạp và có * không có quy tắc "một kích thước phù hợp với tất cả". Luôn luôn sử dụng UTC là tốt cho dấu thời gian, nhưng nó tốt trong các tình huống khác nhau. –

+0

Cảm ơn đoạn thứ hai đó. Tôi đã có một số mã chạy để kiểm tra những thứ trong múi giờ khác nhau nhưng nó không hoạt động vì khởi tạo lười biếng. :( – mao47

Các vấn đề liên quan