DateTime.Now so với DateTime.UtcNow


225

Tôi đã tự hỏi chính xác các nguyên tắc làm thế nào hai tài sản hoạt động. Tôi biết cái thứ hai là phổ quát và về cơ bản không xử lý các múi giờ, nhưng ai đó có thể giải thích chi tiết về cách chúng hoạt động và cái nào nên được sử dụng trong kịch bản nào không?


1
có thể là quá muộn nhưng tôi muốn trỏ đến blog này: blog.eachoflogic.com/2013/10/ trên
Kai Wang

Câu trả lời:


346

DateTime.UtcNow cho bạn biết ngày và giờ như trong Giờ quốc tế phối hợp, còn được gọi là múi giờ trung bình Greenwich - về cơ bản giống như khi bạn ở London England, nhưng không phải vào mùa hè. DateTime. Bây giờ cung cấp ngày và thời gian như nó sẽ xuất hiện cho một người nào đó trong miền địa phương hiện tại của bạn.

Tôi khuyên bạn nên sử dụng DateTime.Nowbất cứ khi nào bạn hiển thị một ngày cho con người - theo cách đó họ cảm thấy thoải mái với giá trị họ nhìn thấy - đó là thứ mà họ có thể dễ dàng so sánh với những gì họ thấy trên đồng hồ hoặc đồng hồ. Sử dụng DateTime.UtcNowkhi bạn muốn lưu trữ ngày hoặc sử dụng chúng cho các tính toán sau này (theo mô hình máy chủ-máy khách), các tính toán của bạn không bị nhầm lẫn bởi các máy khách ở các múi giờ khác nhau từ máy chủ của bạn hoặc từ nhau.


84
một điểm tuyệt vời - khi lưu trữ ngày trong cơ sở dữ liệu hoặc tệp, chắc chắn lưu trữ chúng trong UTC!
Jeff Atwood

15
Bạn phải lưu ý rằng khi bạn muốn lưu trữ ngày trong UTC trong cơ sở dữ liệu, bạn phải đảm bảo rằng cơ sở dữ liệu không thêm múi giờ riêng của mình vào ngày không đưa ra múi giờ rõ ràng. Lưu ý rằng DateTime sẽ luôn sử dụng múi giờ hiện tại khi được yêu cầu.
Omer van Kloeten

@OmervanKloeten cho một điểm rất tốt. Tôi tự hỏi liệu có một giải pháp 'toàn diện' thanh lịch cho việc này, để lưu trữ và nhận ngày chính xác mọi lúc, ngay cả khi máy chủ IIS và SQL của bạn ở các múi giờ khác nhau.
TheGeekZn

1
@ JoshYates1980 Có, bạn chỉ cần thực hiện DateTime.UtcNow.AddYears (1)
CathalMF

3
Sử dụng NodaTime - nó sẽ buộc bạn suy nghĩ về thời gian theo cách hữu ích hơn và tránh những vấn đề như vậy
aateeque

86

Nó thực sự khá đơn giản, vì vậy tôi nghĩ nó phụ thuộc vào đối tượng của bạn và nơi họ sống.

Nếu bạn không sử dụng Utc, bạn phải biết múi giờ của người bạn đang hiển thị ngày và giờ - nếu không bạn sẽ nói với họ điều gì đó xảy ra lúc 3 giờ chiều trong thời gian hệ thống hoặc máy chủ, khi nó thực sự xảy ra lúc 5 giờ chiều họ tình cờ sống

Chúng tôi sử dụng DateTime.UtcNowvì chúng tôi có đối tượng web toàn cầu và vì tôi không muốn cằn nhằn mọi người dùng để điền vào biểu mẫu cho biết họ sống ở múi giờ nào.

Chúng tôi cũng hiển thị thời gian tương đối (2 giờ trước, 1 ngày trước, v.v.) cho đến khi bài đăng đủ tuổi để thời gian "giống nhau" bất kể bạn sống ở đâu trên Trái đất.


Tôi cũng muốn thứ hai rằng việc lưu trữ DateTime.UtcNow cũng chỉ cần thiết khi tính toán với 2 ngày được thực hiện để có được số giờ chính xác. Khi tôi chỉ phải hiển thị Ngày Đăng ký thì Ngày tháng. Bây giờ là đủ.
Elisabeth

36

Cũng lưu ý sự khác biệt hiệu suất; sau đó nhanh hơn DateTime.UtcNowkhoảng 30 lần DateTime.Now, bởi vì bên trong DateTime.Nowđang thực hiện rất nhiều điều chỉnh múi giờ (bạn có thể dễ dàng xác minh điều này với Reflector).

Vì vậy, KHÔNG sử dụng DateTime.Nowcho các phép đo thời gian tương đối.


Nó đã đưa tôi đến một hành trình đau đớn khi biết UtcNow có hiệu suất tốt hơn và chỉ đơn giản là lưu ngày của bạn trong mysql và giả sử đó là utc và so sánh hiển thị phụ thuộc ngày với UtcNow đơn giản hóa các vấn đề múi giờ toàn cầu này
Diin

29

Một khái niệm chính để hiểu trong .NET là hiện naytại khắp nơi trên trái đất không có vấn đề gì múi giờ bạn đang ở trong Vì vậy, nếu bạn nạp một biến với. DateTime.NowHoặc DateTime.UtcNow-. Nhiệm vụ là giống hệt nhau * của bạn DateTimeđối tượng hiểu biết những gì múi giờ bạn đang ở trong và đưa nó vào tài khoản bất kể sự phân công.

Tính hữu dụng DateTime.UtcNowcó ích khi tính toán ngày qua ranh giới Giờ tiết kiệm ánh sáng ban ngày. Đó là, ở những nơi tham gia vào thời gian tiết kiệm ánh sáng ban ngày, đôi khi có 25 giờ từ trưa đến trưa ngày hôm sau, và đôi khi có 23 giờ giữa trưa và trưa ngày hôm sau. Nếu bạn muốn xác định chính xác số giờ từ thời điểm A và thời gian B, trước tiên bạn cần dịch từng số tương đương với UTC của chúng trước khi tính toán TimeSpan.

Điều này được bao phủ bởi một bài đăng blog tôi đã viết để giải thích thêm TimeSpan, và bao gồm một liên kết đến một bài viết MS thậm chí rộng hơn về chủ đề này.

* Làm rõ: Hoặc là chuyển nhượng sẽ lưu trữ thời gian hiện tại. Nếu bạn đã tải hai biến một thông qua DateTime.Now()và người kia qua DateTime.UtcNow()những TimeSpankhác biệt giữa hai sẽ là mili giây, không giờ giả sử bạn đang ở trong một múi giờ giờ đi từ giờ GMT. Như đã lưu ý dưới đây, in ra các Stringgiá trị của chúng sẽ hiển thị các chuỗi khác nhau.


1
Về "tải một biến với DateTime.Now hoặc DateTime.UtcNow - phép gán giống hệt nhau": Điều này có thể cần được làm rõ? Khi tôi ngồi ở đây trong múi giờ EDT (UTC -4), tôi đã gán hai biến cho DateTime.UtcNow và DateTime.Now, sau đó in giá trị của chúng bằng ToString (). Các giá trị được hiển thị cách nhau 4 giờ - không "giống hệt nhau".
Jon Schneider

2
@JonSchneider, tôi tin bạn là chính xác. Câu lệnh: "bài tập giống hệt nhau" là không đúng. ToString () có lẽ không phải là cách tốt nhất để kiểm tra điều đó, bởi vì nó có thể hiển thị các ngày bằng nhau khác nhau (giống như Java). Các chức năng so sánh là một thử nghiệm tốt hơn, và cho thấy chúng thực sự không bằng nhau.
Ted Bigham

Làm rõ với câu lệnh "giống hệt" của tôi: Tải một biến qua DateTime. Bây giờ và một biến khác với DateTime.UtcNow và sau đó in chênh lệch TimeSpan. Sự khác biệt sẽ là mili giây và không phải là giờ giả sử bạn cách giờ GMT.
Máy ảnh Carl

18

Đây là một câu hỏi hay. Tôi đang khôi phục nó để cung cấp thêm một chút chi tiết về cách .Net hành xử với các Kindgiá trị khác nhau . Như @Jan Zich chỉ ra, Đây thực sự là một tài sản cực kỳ quan trọng và được đặt khác nhau tùy thuộc vào việc bạn sử dụng Nowhay UtcNow.

Bên trong ngày được lưu trữ theo Ticksđó (trái với câu trả lời của @Carl Camera) là khác nhau tùy thuộc vào việc bạn sử dụng Nowhay UtcNow.

DateTime.UtcNowcư xử như các ngôn ngữ khác. Nó đặt Ticksthành giá trị dựa trên GMT. Nó cũng đặt Kindra Utc.

DateTime.Nowthay đổi Ticksgiá trị thành giá trị của nó nếu đó là thời gian trong ngày của bạn trong múi giờ GMT . Nó cũng đặt Kindra Local.

Nếu bạn chậm 6 giờ (GMT-6), bạn sẽ nhận được thời gian GMT từ 6 giờ trước. .Net thực sự bỏ qua Kindvà xử lý lần này như thể là 6 giờ trước, mặc dù nó được coi là "bây giờ". Điều này thậm chí còn phá vỡ nhiều hơn nếu bạn tạo một DateTimethể hiện sau đó thay đổi múi giờ của bạn và cố gắng sử dụng nó.

Các trường hợp DateTime với các giá trị 'Loại' khác nhau KHÔNG tương thích.

Hãy xem một số mã ...

    DateTime utc = DateTime.UtcNow;
    DateTime now = DateTime.Now;
    Debug.Log (utc + " " + utc.Kind);  // 05/20/2015 17:19:27 Utc
    Debug.Log (now + " " + now.Kind);  // 05/20/2015 10:19:27 Local

    Debug.Log (utc.Ticks);  // 635677391678617830
    Debug.Log (now.Ticks);  // 635677139678617840

    now = now.AddHours(1);
    TimeSpan diff = utc - now;
    Debug.Log (diff);  // 05:59:59.9999990

    Debug.Log (utc <  now);  // false
    Debug.Log (utc == now);  // false
    Debug.Log (utc >  now);  // true

    Debug.Log (utc.ToUniversalTime() <  now.ToUniversalTime());  // true
    Debug.Log (utc.ToUniversalTime() == now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() >  now.ToUniversalTime());  // false
    Debug.Log (utc.ToUniversalTime() -  now.ToUniversalTime());  // -01:00:00.0000010

Như bạn có thể thấy ở đây, các phép so sánh và hàm toán học không tự động chuyển đổi thành thời gian tương thích. Đáng Timespanlẽ đã gần một giờ, nhưng thay vào đó là gần 6. "utc <now" đáng lẽ phải đúng (tôi thậm chí đã thêm một giờ để chắc chắn), nhưng vẫn sai.

Bạn cũng có thể thấy 'công việc xung quanh', đơn giản là chuyển đổi sang thời gian phổ quát ở bất cứ nơi nào Kindkhông giống nhau.

Câu trả lời trực tiếp của tôi cho câu hỏi đồng ý với đề xuất của câu trả lời được chấp nhận về thời điểm sử dụng mỗi câu hỏi. Bạn phải luôn cố gắng làm việc với DateTimecác đối tượng có Kind=Utc, ngoại trừ trong quá trình i / o (hiển thị và phân tích cú pháp). Điều này có nghĩa là bạn hầu như luôn luôn được sử dụng DateTime.UtcNow, ngoại trừ các trường hợp bạn đang tạo đối tượng chỉ để hiển thị nó và loại bỏ nó ngay lập tức.


7

DateTime không biết múi giờ là gì. Nó luôn luôn giả định rằng bạn đang ở địa phương của bạn. UtcNow chỉ có nghĩa là "Trừ múi giờ của tôi từ thời điểm đó".

Nếu bạn muốn sử dụng ngày nhận biết múi giờ, hãy sử dụng DateTimePackset , đại diện cho ngày / giờ với múi giờ. Tôi đã phải học điều đó một cách khó khăn.


9
Để hoàn toàn chính xác (và tránh mọi người sử dụng Now over UtcNow vì lý do hiệu suất), đó là một cách khác: Bây giờ thêm múi giờ vào UtcNow và thực tế là chậm hơn rất nhiều.
mafu

5

Câu trả lời "đơn giản" cho câu hỏi là:

DateTime.Now trả về giá trị DateTime biểu thị thời gian hiện tại của hệ thống (theo bất kỳ múi giờ nào mà hệ thống đang chạy). Các DateTime.Kind bất động sản sẽ được DateTimeKind.Local

DateTime.UtcNow trả về giá trị DateTime đại diện cho Thời gian phối hợp phổ biến hiện tại (còn gọi là UTC) sẽ giống nhau bất kể múi giờ của hệ thống. Các DateTime.Kind bất động sản sẽ được DateTimeKind.Utc


4

Chỉ cần thêm một chút vào các điểm đã nêu ở trên: cấu trúc DateTime cũng chứa một trường ít được biết đến có tên là Kind (ít nhất, tôi đã không biết về nó trong một thời gian dài). Về cơ bản, nó chỉ là một lá cờ cho biết thời gian là cục bộ hay UTC; nó không chỉ định phần bù thực từ UTC cho giờ địa phương. Bên cạnh thực tế là nó chỉ ra ý định nào mà ống dẫn được xây dựng, nó cũng ảnh hưởng đến cách thức các phương thức ToUniversalTime ()ToLocalTime () hoạt động.



1

DateTime.UtcNow là thang thời gian liên tục, có giá trị đơn, trong khi DateTime.Now không liên tục hoặc có giá trị đơn. Lý do chính là Giờ tiết kiệm ánh sáng ban ngày, không áp dụng cho UTC. Vì vậy, UTC không bao giờ nhảy tiến hoặc lùi một giờ, trong khi giờ địa phương (DateTime.Now) thì không. Và khi nó nhảy lùi lại, cùng một giá trị thời gian xảy ra hai lần.


1

DateTime.UtcNow là thang đo thời gian toàn cầu bỏ qua Giờ tiết kiệm ánh sáng ban ngày. Vì vậy, UTC không bao giờ thay đổi do DST.

Nhưng, DateTime.Now không liên tục hoặc có giá trị đơn vì nó thay đổi theo DST. Có nghĩa là DateTime. Bây giờ, cùng một giá trị thời gian có thể xảy ra hai lần khiến khách hàng rơi vào trạng thái bối rối.


0

Khi bạn cần thời gian cục bộ cho máy, ứng dụng của bạn chạy tại (như CEST cho Châu Âu), hãy sử dụng Ngay. Nếu bạn muốn một thời gian phổ quát - UtcNow. Đó chỉ là vấn đề sở thích của bạn - có thể là tạo một trang web / ứng dụng độc lập mà bạn muốn sử dụng thời gian mà người dùng đã sử dụng - bị ảnh hưởng bởi cài đặt múi giờ của anh ấy / cô ấy - DateTime.Now.

Chỉ cần nhớ, đối với một trang web, đó là cài đặt múi giờ của máy chủ. Vì vậy, nếu bạn đang hiển thị thời gian cho người dùng, hãy lấy múi giờ ưa thích của mình và thay đổi thời gian (chỉ cần tiết kiệm thời gian Utc vào cơ sở dữ liệu và sửa đổi nó) hoặc chỉ định UTC. Nếu bạn quên làm như vậy, người dùng có thể thấy một cái gì đó như: đã đăng 3 điểm trừ trước và sau đó một thời gian trong tương lai gần nó :)


0

Sự khác biệt lớn :) là DateTime.Now không được hỗ trợ trong SharePoint Workflow, bạn phải sử dụng DateTime.UtcNow

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.