Datetime vs DatetimeOffset

Dịch từ: Câu trả lời của Matt Johnson-Pint trên StackOverflow

DatetimeOffset là đại diện cho thời gian tức thời (cũng có thể được biết đến là thời gian tuyệt đối). Bởi đó, ý tôi là một khoảnh khắc thời gian mà mọi người đều hiểu (không tính giây nhuận), hoặc tác động tương đối của thời gian giãn nở). Một cách khác để hiện diện cho thời gian tức thời là với một DateTime.KindDateTimeKind.Utc.

Đây là sự khác biệt với calendar time (hoặc được biết là civil time), một vị trí ở một cuốn lịch của một người nào đó, và nhiều cuốn lịch khác nhau trên toàn cầu. Chúng ta gọi những cái lịch đó là múi giờ. Calendar time là hiện diện bằng một DateTime.KindDateTimeKind.Unspecified, hoặc DateTimeKind.Local. Và .Local chỉ có ý nghĩa trong ngữ cảnh bạn hiểu được rằng bạn đang cần sử dụng kết quả từ máy tính. (Ví dụ, khi bạn đi chơi net) 

Vậy thì, tại sao lại sử dụng DatetimeOffset thay vì một UTC DateTime? Nó tùy thuộc vào quan điểm cá nhân. Hãy thử dùng phép loại suy - chúng ta sẽ giả thành những người nhiếp ảnh.

Tưởng tượng là bạn đang đứng trên một calendar timeline, chĩa cái camera vào một người đang đứng trên instantaneous timeline (dòng thời gian tức thời) đặt trước mặt bạn, Bạn sắp xếp camera của bạn theo như quy luật của múi giờ của bạn - nghĩa là thay đổi định kỳ do tiết kiệm ánh sáng ban ngày, hoặc do những thức khác thay đổi định nghĩa múi giờ của bạn. (Ví dụ như là bạn không vững tay nên camera của bạn bị rung) 

Người đang đứng trong bức ảnh sẽ thấy góc mà camera của bạn hướng tới. Nếu những camera khác đang chụp, thì họ sẽ có nhiều góc khác nhau. Đây là phần Offset trong DatetimeOffset thể hiện.

Nên nếu bạn gắn nhãn camera của bạn là "Eastern Time", đôi khi bạn chĩa từ -5, và đôi khi bạn đang đến -4. Có rất nhiều camera khắp nơi trên thế giới, nhiều nhãn khác nhau, và tất cả chĩa đến cùng một dòng thời gian tức thời từ nhiều góc nhìn khác nhau. Một vài trong chúng là nằm bên cạnh (hoặc trên cùng) nhau, vì thế chỉ biết độ lệch thì không đủ để xác định múi giờ liên quan. 

Và còn UTC là gì? Queo, nó là cái camera vững nhất ở ngoài kia. Nó ở trên cái giá ba chân, neo chặt ở dưới đất và không nhúc nhích. Chúng ta gọi góc nhìn của nó là độ lệch 0.


Vậy - phép loại suy này nói lên điều gì? Nó đưa ra một vài hướng dẫn trực quan.

  • Nếu bạn đang diễn tả thời gian tương đối đến một vài nơi cụ thể, diễn tả nó trong calendar time với DateTime. Chỉ cần chắc chắn bạn không bối rối với một calendar khác. Unspecified nên trong giả thiết của bạn. Local là chỉ hữu ích từ DateTime.Now. Ví dụ, tôi có thể lấy DateTime.Now và lưu nó ở database - nhưng khi tôi lấy nó lên, tôi phải thừ nhận là nó Unspecified. Tôi không thể tin vào local calendar là một calendar mà tôi lấy từ ban đầu.
  • Nếu bạn phải luôn luôn chắc chắn vào mọi thời điểm, hãy đảm bảo bạn đang thể hiện thời gian tức thời. Sử dụng DateTimeOffset để làm việc đó, hoặc sử dụng UTC DateTime bằng quy ước.
  • Nếu bạn cần phải theo dõi một khoảnh khắc của thời gian tức thời, nhưng bạn cũng muốn biết "Mấy giờ người dùng nghĩ về local calendar của họ?" - thì khi đó bạn hãy sử dụng DateTimeOffset. Điều này rất quan trọng cho hệ thống quản lý thời gian, ví dụ - cả về kỹ thuật và liên quan hợp pháp.
  • Nếu bạn cần chỉnh sửa một DateTimeOffset được ghi lại trước đó - bạn không có đủ thông tin trong về độ lệch để chắc chắn rằng độ lệch mới là vẫn liên quan đến người dùng. Bạn cũng phải lưu lại múi giờ định danh (nghĩ - Tôi cần tên của camera vì thế tôi có thể chụp tấm ảnh mới nếu vị trí thay đổi)
    • Noda Time có một cái được gọi là ZonedDateTime, trong khi thư viện lớp cơ bản trong .NET không có cái tương tự. Bạn cần giữ cả hai DateTimeOffset và giá trị TimeZoneInfo.Id 
  • Thỉnh thoảng, bạn sẽ muốn diễn tả calendar time là local "khi ai đó nhìn vào". Ví dụ, khi định nghĩa hôm nay là gì. Hôm nay là luôn luôn là giữa đêm đến giữa đêm, nhưng chúng thể hiện gần như vô hạn các phạm vi chồng chéo trên dòng thời gian tức thời. (Trong thực tế chúng ta có một dãy múi giờ cụ thể, nhưng bạn có thể diễn đạt độ chênh lệch bằng cách tick lên xuống). Vì thế trong những tình huống như này, hãy đảm bảo bạn hiểu cách hạn chế hỏi câu hỏi "ai đang hỏi?" đến một múi giờ, hoặc việc chuyển chúng thành thời gian tức thời nếu thích hợp.
Dưới đây là một vài điều nhỏ về DateTimeOffset mà giúp ích cho phép loại suy trên, và vài lời khuyên để hiểu đúng:
  • Nếu bạn so sánh hai giá trị DateTimeOffset, đầu tiên nó chuẩn hóa thành độ lệch 0 trước khi so sánh. Nói cách khác 2012-01-01T00:00:00+00:002012-01-01T02:00:00+02:00 là cùng một khoảnh khắc tức thời nên nó tương đương nhau.
  • Nếu bạn đang sử dụng bất kỳ unit test nào và cần chính xác độ lệch, test cả hai giá trị DateTimeOffset.Offset tách biệt nhau.
  • Có một cách chuyển đổi ngầm được tích hợp trong .NET framework cho phép bạn truyền DateTime vào bất kỳ biến hoặc tham số DateTimeOffset nào. Khi làm như vậy, thì .Kind gặp nhiều vấn đề. Nếu bạn truyền một UTC kind, nó sẽ có thêm độ lệch 0, còn nếu bạn truyền .Local hoặc .Unspecified nó sẽ tự xem đó là Local. Framework nó nói đơn giản là "Queo, bạn kêu tui đổi từ calendar time thành thời gian tức thời, nhưng bạn hông cho tui biết bạn đến từ đâu, nên tui dùng theo lịch địa phương luôn." Đây là một lỗi rất lớn nếu bạn load một DateTime không xác định trên máy tính của bạn với một múi giờ khác. (Theo tôi - thì nó nên quăng exception - nhưng nó lại không làm vậy)

Nhận xét

Bài đăng phổ biến