DateTime.Now vs. DateTime.UtcNow

225

Saya sudah bertanya-tanya apa sebenarnya prinsip-prinsip bagaimana kedua properti itu bekerja. Saya tahu yang kedua bersifat universal dan pada dasarnya tidak berurusan dengan zona waktu, tetapi bisakah seseorang menjelaskan secara rinci bagaimana mereka bekerja dan mana yang harus digunakan dalam skenario apa?

Slavo
sumber
1
mungkin sudah terlambat tetapi saya ingin menunjukkan ke blog ini: blog.angeloflogic.com/2013/10/…
Kai Wang
small bench-marking rextester.com/QRDR82396
Daniel B

Jawaban:

346

DateTime.UtcNow memberi tahu Anda tanggal dan waktu seperti di Waktu Universal Terkoordinasi, yang juga disebut zona waktu Waktu Rata-rata Greenwich - pada dasarnya seperti jika Anda berada di London, Inggris, tetapi tidak selama musim panas. DateTime.Now memberikan tanggal dan waktu seperti yang akan muncul kepada seseorang di lokal Anda saat ini.

Saya sarankan menggunakan DateTime.Nowsetiap kali Anda menampilkan tanggal untuk seorang manusia - dengan cara itu mereka merasa nyaman dengan nilai yang mereka lihat - itu adalah sesuatu yang mereka dapat dengan mudah dibandingkan dengan apa yang mereka lihat di jam tangan atau jam mereka. Gunakan DateTime.UtcNowketika Anda ingin menyimpan tanggal atau menggunakannya untuk perhitungan nanti seperti itu (dalam model client-server) perhitungan Anda tidak menjadi bingung oleh klien di zona waktu yang berbeda dari server Anda atau dari satu sama lain.

Blair Conrad
sumber
84
titik yang sangat baik - ketika menyimpan tanggal dalam database atau file, pasti menyimpannya dalam UTC!
Jeff Atwood
15
Anda harus mencatat bahwa ketika Anda ingin menyimpan tanggal dalam UTC dalam database, Anda harus memastikan bahwa database tidak menambahkan zona waktu sendiri ke tanggal yang tidak memberikan zona waktu eksplisit. Perhatikan bahwa DateTime akan selalu menggunakan zona waktu saat ini ketika diminta.
Omer van Kloeten
@OmervanKloeten memberikan poin yang sangat bagus. Saya bertanya-tanya apakah ada solusi elegan 'serba' untuk ini, untuk menyimpan dan menerima tanggal dengan benar setiap kali, bahkan jika IIS dan SQL server Anda berada di zona waktu yang berbeda.
TheGeekZn
1
@ JoshYates1980 Ya, Anda baru saja melakukan DateTime.UtcNow.AddYears (1)
CathalMF
3
Gunakan NodaTime - itu akan memaksa Anda berpikir tentang waktu dengan cara yang lebih berguna dan menghindari masalah seperti itu
aateeque
86

Ini sangat sederhana, jadi saya pikir itu tergantung pada audiens Anda dan di mana mereka tinggal.

Jika Anda tidak menggunakan Utc, Anda harus mengetahui zona waktu orang yang Anda tampilkan tanggal dan waktunya - jika tidak, Anda akan memberi tahu mereka sesuatu terjadi pada jam 3 sore dalam waktu sistem atau server, ketika itu benar-benar terjadi pada jam 5 sore di mana mereka kebetulan hidup.

Kami menggunakan DateTime.UtcNowkarena kami memiliki pemirsa web global, dan karena saya lebih suka tidak mengomel setiap pengguna untuk mengisi formulir yang menunjukkan zona waktu mereka tinggal.

Kami juga menampilkan waktu relatif (2 jam yang lalu, 1 hari yang lalu, dll) sampai pos cukup umur sehingga waktunya "sama" di mana pun di Bumi Anda tinggal.

Jeff Atwood
sumber
Saya ingin juga yang kedua yang menyimpan DateTime.UtcNow juga hanya diperlukan ketika perhitungan dengan 2 tanggal dilakukan untuk mendapatkan jam yang benar. Ketika saya hanya perlu menampilkan Tanggal RegisterAt maka Datetime. Sekarang sudah cukup.
Elisabeth
36

Perhatikan juga perbedaan kinerja; DateTime.UtcNowada di suatu tempat sekitar 30 kali lebih cepat DateTime.Now, karena secara internal DateTime.Nowmelakukan banyak penyesuaian zona waktu (Anda dapat dengan mudah memverifikasi ini dengan Reflector).

Jadi JANGAN gunakan DateTime.Nowuntuk pengukuran waktu relatif.

Magnus Krisell
sumber
Butuh perjalanan yang menyakitkan bagi saya. UtcNow memiliki kinerja yang lebih baik dan hanya menyimpan tanggal Anda di mysql dan dengan asumsi itu adalah utc dan membandingkan tampilan yang tergantung tanggal dengan UtcNow menyederhanakan masalah zona waktu global ini
Diin
29

Salah satu konsep utama untuk memahami di NET adalah bahwa sekarang adalah saat seluruh bumi tidak peduli apa zona waktu Anda berada di Jadi jika Anda memuat variabel dengan. DateTime.NowAtau DateTime.UtcNow-. Penugasan identik * Anda DateTimeobjek tahu apa TimeZone Anda berada di dan memperhitungkannya terlepas dari penugasannya.

Kegunaan DateTime.UtcNowsangat berguna saat menghitung tanggal melintasi batas Waktu Daylight Savings. Artinya, di tempat-tempat yang berpartisipasi dalam penghematan waktu siang hari, kadang-kadang ada 25 jam dari siang sampai siang hari berikutnya, dan kadang-kadang ada 23 jam antara siang dan siang hari berikutnya. Jika Anda ingin menentukan dengan benar jumlah jam dari waktu A dan waktu B, Anda harus terlebih dahulu menerjemahkan masing-masing ke setara UTC mereka sebelum menghitung TimeSpan.

Ini dicakup oleh posting blog yang saya tulis yang menjelaskan lebih lanjut TimeSpan, dan termasuk tautan ke artikel MS yang bahkan lebih luas tentang topik tersebut.

* Klarifikasi: Tugas mana pun akan menyimpan waktu saat ini. Jika Anda adalah untuk memuat dua variabel satu melalui DateTime.Now()dan lainnya melalui DateTime.UtcNow()para TimeSpanperbedaan antara dua akan milidetik, bukan jam dengan asumsi Anda berada dalam zona waktu jam dari GMT. Seperti disebutkan di bawah, mencetak Stringnilainya akan menampilkan string yang berbeda.

Carl Camera
sumber
1
Mengenai "memuat variabel dengan DateTime.Now atau DateTime.UtcNow - tugasnya identik": Ini mungkin perlu diklarifikasi? Saat saya duduk di zona waktu EDT (UTC -4), saya menetapkan dua variabel untuk DateTime.UtcNow dan DateTime.Now masing-masing, dan kemudian mencetak nilainya dengan ToString (). Nilai yang ditampilkan terpisah 4 jam - tidak "identik."
Jon Schneider
2
@ JonSchneider, saya yakin Anda benar. Pernyataan: "penugasan itu identik" tidak benar. ToString () mungkin bukan cara terbaik untuk mengujinya, karena dapat menampilkan tanggal yang sama secara berbeda (seperti yang dilakukan Java). Fungsi perbandingan adalah tes yang lebih baik, dan menunjukkan mereka memang tidak sama.
Ted Bigham
Klarifikasi ke pernyataan "identik" saya: Muat satu variabel melalui DateTime.Now dan lainnya dengan DateTime.UtcNow dan kemudian cetak perbedaan TimeSpan. Perbedaannya adalah milidetik dan bukan jam dengan asumsi Anda berada beberapa jam lagi dari GMT.
Carl Camera
18

Ini pertanyaan yang bagus. Saya menghidupkannya kembali untuk memberikan sedikit detail tentang bagaimana .Net berperilaku dengan Kindnilai yang berbeda . Seperti yang ditunjukkan oleh @Jan Zich, Ini sebenarnya properti yang sangat penting dan diatur secara berbeda tergantung pada apakah Anda menggunakan Nowatau UtcNow.

Secara internal tanggal disimpan sebagai Ticks(berbeda dengan jawaban @Carl Camera) berbeda tergantung pada apakah Anda menggunakan Nowatau UtcNow.

DateTime.UtcNowberperilaku seperti bahasa lain. Ini ditetapkan Tickske nilai berdasarkan GMT. Ini juga diatur Kindke Utc.

DateTime.Nowmengubah Ticksnilai menjadi seperti apa jadinya waktu Anda di zona waktu GMT . Ini juga diatur Kindke Local.

Jika Anda 6 jam di belakang (GMT-6), Anda akan mendapatkan waktu GMT dari 6 jam yang lalu. Net sebenarnya mengabaikan Kinddan memperlakukan kali ini seolah-olah itu 6 jam yang lalu, meskipun itu seharusnya "sekarang". Hal ini semakin terpecah jika Anda membuat DateTimeinstance lalu mengubah zona waktu Anda dan mencoba menggunakannya.

Contoh DateTime dengan nilai 'Jenis' yang berbeda TIDAK kompatibel.

Mari kita lihat beberapa kode ...

    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

Seperti yang dapat Anda lihat di sini, perbandingan dan fungsi matematika tidak secara otomatis dikonversi ke waktu yang kompatibel. The Timespanseharusnya hampir satu jam, melainkan hampir 6. "utc <sekarang" seharusnya benar (Aku bahkan menambahkan satu jam untuk memastikan), tapi masih palsu.

Anda juga dapat melihat 'bekerja di sekitar' yang hanya mengkonversi ke waktu universal di mana saja yang Kindtidak sama.

Jawaban langsung saya atas pertanyaan tersebut setuju dengan rekomendasi jawaban yang diterima tentang kapan harus menggunakan masing-masing. Anda harus selalu mencoba untuk bekerja dengan DateTimebenda - benda yang ada Kind=Utc, kecuali selama i / o (displaying dan parsing). Ini berarti Anda harus hampir selalu menggunakan DateTime.UtcNow, kecuali untuk kasus di mana Anda membuat objek hanya untuk menampilkannya, dan segera membuangnya.

Ted Bigham
sumber
7

DateTime tidak tahu apa zona waktu itu. Itu selalu mengasumsikan Anda berada di waktu setempat. UtcNow hanya berarti "Kurangi zona waktu saya dari waktu".

Jika Anda ingin menggunakan tanggal yang diketahui oleh zona waktu, gunakan DateTimeOffset , yang mewakili tanggal / waktu dengan zona waktu. Saya harus belajar itu dengan cara yang sulit.

Omer van Kloeten
sumber
9
Untuk lebih tepatnya (dan menghindari orang menggunakan Now over UtcNow karena alasan kinerja), ini sebaliknya: Sekarang menambahkan zona waktu ke UtcNow dan pada kenyataannya jauh lebih lambat.
mafu
5

Jawaban "sederhana" untuk pertanyaan ini adalah:

DateTime. Sekarang mengembalikan nilai DateTime yang mewakili saat ini, waktu sistem (dalam zona waktu apa pun sistem berjalan). The DateTime.Kind properti akan DateTimeKind.Local

DateTime.UtcNow mengembalikan nilai DateTime yang mewakili Waktu Koordinasi Universal saat ini (alias UTC) yang akan tetap sama terlepas dari zona waktu sistem. The DateTime.Kind properti akan DateTimeKind.Utc

PapillonUK
sumber
4

Hanya sedikit tambahan untuk poin yang dibuat di atas: struct DateTime juga mengandung sedikit bidang yang dikenal disebut Kind (setidaknya, saya tidak tahu tentang itu untuk waktu yang lama). Ini pada dasarnya hanya sebuah bendera yang menunjukkan apakah waktu bersifat lokal atau UTC; itu tidak menentukan offset nyata dari UTC untuk waktu lokal. Selain fakta bahwa itu menunjukkan dengan niat apa stuct dibangun, itu juga mempengaruhi cara bagaimana metode ToUniversalTime () dan ToLocalTime () bekerja.

Jan Zich
sumber
1

DateTime.UtcNow adalah skala waktu bernilai tunggal yang berkelanjutan, sedangkan DateTime.Now tidak berkelanjutan atau bernilai tunggal. Alasan utamanya adalah Daylight Savings Time, yang tidak berlaku untuk UTC. Jadi UTC tidak pernah melompat maju atau mundur satu jam, sedangkan waktu setempat (DateTime.Now) tidak. Dan ketika itu melompat mundur, nilai waktu yang sama terjadi dua kali.

pengguna1315023
sumber
1

DateTime.UtcNow adalah skala waktu Universal menghilangkan Daylight Savings Time. Jadi UTC tidak pernah berubah karena DST.

Tapi, DateTime. Sekarang tidak berkelanjutan atau bernilai tunggal karena itu berubah sesuai dengan DST. Yang berarti DateTime. Sekarang, nilai waktu yang sama dapat terjadi dua kali meninggalkan pelanggan dalam keadaan bingung.

ChaiVan
sumber
0

Saat Anda membutuhkan waktu lokal untuk mesin yang menjalankan aplikasi Anda (seperti CEST untuk Eropa), gunakan Sekarang. Jika Anda ingin waktu universal - UtcNow. Ini hanya masalah preferensi Anda - mungkin membuat situs web lokal / aplikasi mandiri yang Anda ingin menggunakan waktu yang dimiliki pengguna - sangat terpengaruh oleh pengaturan zona waktunya - DateTime.Now.

Hanya ingat, untuk situs web itu adalah pengaturan zona waktu server. Jadi jika Anda menampilkan waktu untuk pengguna, dapatkan zona waktu pilihannya dan ubah waktu (cukup simpan waktu Utc ke basis data, dan modifikasi) atau tentukan UTC. Jika Anda lupa melakukannya, pengguna dapat melihat sesuatu seperti: mem-posting 3 minus lalu dan suatu saat di masa depan dekat itu :)

kender
sumber
0

Perbedaan besar :) adalah DateTime.Now tidak didukung di SharePoint Workflow Anda harus menggunakan DateTime.UtcNow

Michel LAPLANE
sumber