2013-10-17 16 views
9

Tôi có một tình huống mà tôi muốn chuyển đổi một số DateTime thành một số Instant. Tôi tin rằng số Kind của DateTime sẽ là Local.Tôi nên chuyển đổi DateTime cục bộ thành Instant như thế nào?

Cho rằng các DateTime là trong một biến gọi là time, gần nhất tôi có thể tìm thấy trong thư viện là:

Instant.FromDateTimeUtc(time.ToUniversalTime()) 

Điều này có vẻ hợp lý, nhưng tôi muốn chắc chắn rằng điều này là hoàn toàn đáng tin cậy và doesn' t có nguy cơ mất dữ liệu hoặc tham nhũng. Tôi không chắc chắn nếu đây là cách tốt nhất để làm việc chuyển đổi hoặc nếu có một phương tiện đáng tin cậy hơn để làm như vậy.

Tôi nhìn trang BCL Conversions NodaTime, và nó nói như sau về kịch bản này:

Lưu ý rằng không có chuyển đổi đến một DateTime với một loại Local - điều này một cách hiệu quả sẽ cho thời gian mặc định hệ thống khu vực, mà bạn thường nên rõ ràng về để bắt đầu với.

Trả lời

16

Bạn đang thiếu một điểm quan trọng: A DateTime loại nào là Local không phải lúc nào cũng đại diện cho một khoảnh khắc độc đáo kịp thời. Đó là lý do tại sao không có ánh xạ trực tiếp tới một số Instant.

Trong quá trình chuyển đổi DST bị thu gọn, một địa phương DateTime có thể là một trong hai khoảnh khắc có thể có trong thời gian. Nếu bạn định chuyển đổi nó thành một số Instant, thì ở đâu đó bạn cần quyết định thời điểm nào bạn nên chọn.

Trong câu trả lời bạn đã cho, tôi giả sử bạn có được timezone từ một trong các cách sau:

var timezone = DateTimeZoneProviders.Tzdb.GetSystemDefault(); 

hoặc

var timezone = DateTimeZoneProviders.Bcl.GetSystemDefault(); 

Hoặc là ok cho nhiệm vụ này. Sau đó, các mã bạn đã cho:

var localTime = LocalDateTime.FromDateTime(time); 
var zonedTime = localTime.InZoneStrictly(timeZone); 
return zonedTime.ToInstant(); 

Đây chính là chính xác, nhưng kể từ khi bạn sử dụng InZoneStrictly, bạn sẽ nhận được một AmbiguousTimeException trong quá trình chuyển mùa thu trở lại.

Bạn có thể tránh điều này bằng cách sử dụng InZoneLeniently, thao tác này sẽ chọn sau hai khả năng (thường là thời gian "Chuẩn"). Nhưng quan trọng hơn, thay vào đó, bạn có thể sử dụng InZone và cung cấp resolver tiêu chuẩn hoặc tùy chỉnh để kiểm soát hành vi chính xác hơn.

Về cách tiếp cận ban đầu của bạn về:

Instant.FromDateTimeUtc(time.ToUniversalTime()) 

Đây là ok và sẽ không bị hỏng dữ liệu của bạn, nhưng hiểu rằng nó sẽ dựa vào hành vi của BCL của địa phương để chuyển đổi phổ quát. Nó giống hệt với InZoneLeniently, trong đó một giá trị mơ hồ sẽ được coi là thời gian "chuẩn".

Đây là ví dụ tuyệt vời về cách NodaTime cung cấp API chính xác hơn. Thay vì đưa ra các giả định, bạn có cơ hội để cụ thể và cung cấp hành vi tùy chỉnh. Cuối cùng, bạn đã đạt được kết quả tương tự, nhưng nó đưa vấn đề này lên nền trước thay vì ẩn nó.

+0

Cảm ơn bạn đã dành thời gian giải thích điều này. Tôi nghĩ điều này sẽ hữu ích cho những người mới đến thư viện. – Sam

1

Tôi chỉ nhận ra rằng tôi có thể chuyển đổi theo giờ địa phương đến một NodaTimeLocalDateTime và sau đó bản đồ nó để ngay lập tức bằng cách sử dụng một trong những phương pháp InZone Tiếp theo ToInstant. Dưới đây là một ví dụ giả sử múi giờ của thời gian được quy định tại timeZone và bạn muốn có một lỗi được ném nếu thời gian là không hợp lệ:

var localTime = LocalDateTime.FromDateTime(time); 
var zonedTime = localTime.InZoneStrictly(timeZone); 
return zonedTime.ToInstant(); 

Hãy ghi nhớ rằng đây là giả định rằng time thực sự là Local. Nếu không, tôi tin rằng kết quả sẽ không chính xác.

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