Saat ini, kami memiliki cara standar untuk berurusan dengan .NET DateTime
dalam cara sadar TimeZone: Setiap kali kami memproduksi, DateTime
kami melakukannya di UTC (mis. Menggunakan DateTime.UtcNow
), dan setiap kali kami menampilkannya, kami mengonversi kembali dari UTC ke waktu setempat pengguna. .
Itu bekerja dengan baik, tapi saya sudah membaca tentang DateTimeOffset
dan bagaimana ia menangkap waktu lokal dan UTC di objek itu sendiri. Jadi pertanyaannya adalah, apa manfaat menggunakan DateTimeOffset
dibandingkan dengan apa yang telah kita lakukan?
Jawaban:
DateTimeOffset
adalah representasi waktu sesaat (juga dikenal sebagai waktu absolut ). Maksud saya adalah momen dalam waktu yang bersifat universal untuk semua orang (tidak memperhitungkan detik kabisat , atau efek relativistik dari pelebaran waktu ). Cara lain untuk mewakili waktu sesaat adalah denganDateTime
mana.Kind
adalahDateTimeKind.Utc
.Ini berbeda dari waktu kalender (juga dikenal sebagai waktu sipil ), yang merupakan posisi pada kalender seseorang, dan ada banyak kalender berbeda di seluruh dunia. Kami menyebut zona waktu kalender ini . Waktu kalender diwakili oleh
DateTime
mana.Kind
adalahDateTimeKind.Unspecified
, atauDateTimeKind.Local
. Dan.Local
hanya bermakna dalam skenario di mana Anda memiliki pemahaman tersirat di mana komputer yang menggunakan hasil diposisikan. (Misalnya, stasiun kerja pengguna)Jadi, mengapa
DateTimeOffset
bukan UTCDateTime
? Ini semua tentang perspektif. Mari kita gunakan analogi - kita akan berpura-pura menjadi fotografer.Bayangkan Anda berdiri di garis waktu kalender, mengarahkan kamera ke seseorang di garis waktu sesaat yang diletakkan di depan Anda. Anda mengatur kamera berdasarkan aturan zona waktu Anda - yang berubah secara berkala karena waktu musim panas, atau karena perubahan lain pada definisi hukum zona waktu Anda. (Anda tidak memiliki tangan yang mantap, jadi kamera Anda goyah.)
Orang yang berdiri di foto akan melihat dari sudut mana kamera Anda berasal. Jika orang lain mengambil foto, mereka bisa dari sudut yang berbeda. Inilah yang diwakili oleh
Offset
bagian ituDateTimeOffset
.Jadi jika Anda memberi label pada kamera "Waktu Timur", terkadang Anda menunjuk dari -5, dan kadang-kadang Anda menunjuk dari -4. Ada kamera di seluruh dunia, semuanya berlabel hal yang berbeda, dan semua menunjuk pada garis waktu instan yang sama dari sudut yang berbeda. Beberapa dari mereka tepat di sebelah (atau di atas) satu sama lain, jadi hanya mengetahui offset tidak cukup untuk menentukan zona waktu yang terkait dengan waktu.
Dan bagaimana dengan UTC? Nah, itu satu-satunya kamera di luar sana yang dijamin memiliki tangan mantap. Ada di atas tripod, dengan kuat berlabuh ke tanah. Itu tidak ke mana-mana. Kami menyebut sudut pandangnya sebagai titik nol.
Jadi - apa yang dikatakan analogi ini kepada kita? Ini memberikan beberapa panduan intuitif-
Jika Anda merepresentasikan waktu relatif terhadap tempat tertentu, wakili waktu kalender dengan a
DateTime
. Pastikan Anda tidak pernah mengacaukan satu kalender dengan yang lain.Unspecified
harus menjadi asumsi Anda.Local
hanya bermanfaat dariDateTime.Now
. Sebagai contoh, saya mungkin mendapatkanDateTime.Now
dan menyimpannya dalam database - tetapi ketika saya mengambilnya, saya harus berasumsi bahwa itu adalah databaseUnspecified
. Saya tidak dapat mengandalkan bahwa kalender lokal saya adalah kalender yang sama dengan aslinya.Jika Anda harus selalu yakin akan momen tersebut, pastikan Anda mewakili waktu instan. Gunakan
DateTimeOffset
untuk menegakkannya, atau menggunakan UTCDateTime
dengan konvensi.Jika Anda perlu melacak waktu sesaat, tetapi Anda juga ingin tahu "Jam berapa pengguna pikir itu ada di kalender lokal mereka?" - maka Anda harus menggunakan a
DateTimeOffset
. Ini sangat penting untuk sistem ketepatan waktu, misalnya - baik untuk masalah teknis dan hukum.Jika Anda perlu memodifikasi rekaman sebelumnya
DateTimeOffset
- Anda tidak memiliki informasi yang cukup di offset saja untuk memastikan bahwa offset baru masih relevan bagi pengguna. Anda juga harus menyimpan pengenal zona waktu (pikirkan - Saya perlu nama kamera itu sehingga saya dapat mengambil gambar baru meskipun posisinya telah berubah).Juga harus ditunjukkan bahwa Noda Time memiliki representasi yang disebut
ZonedDateTime
untuk ini, sedangkan perpustakaan kelas .Net tidak memiliki hal yang serupa. Anda harus menyimpan nilaiDateTimeOffset
danTimeZoneInfo.Id
nilai.Kadang-kadang, Anda ingin mewakili waktu kalender yang bersifat lokal untuk "siapa pun yang melihatnya". Misalnya, ketika mendefinisikan apa artinya hari ini . Hari ini selalu tengah malam hingga tengah malam, tetapi ini mewakili jumlah tumpang tindih yang hampir tak terbatas pada garis waktu sesaat. (Dalam praktiknya kami memiliki sejumlah zona waktu yang terbatas, tetapi Anda dapat mengimbangi hingga tanda centang). Jadi dalam situasi ini, pastikan Anda memahami cara membatasi "siapa yang bertanya?" pertanyaan ke zona waktu tunggal, atau berurusan dengan menerjemahkannya kembali ke waktu sesaat yang sesuai.
Berikut adalah beberapa bagian lain tentang hal
DateTimeOffset
itu yang mendukung analogi ini, dan beberapa tips untuk menjaganya agar tetap lurus:Jika Anda membandingkan dua
DateTimeOffset
nilai, mereka pertama dinormalisasi ke nol offset sebelum membandingkan. Dengan kata lain,2012-01-01T00:00:00+00:00
dan2012-01-01T02:00:00+02:00
merujuk pada momen instan yang sama, dan karenanya setara.Jika Anda melakukan setiap pengujian unit dan kebutuhan untuk menjadi tertentu dari offset, tes kedua yang
DateTimeOffset
nilai, dan.Offset
properti secara terpisah.Ada konversi implisit satu arah yang dibangun ke dalam kerangka .Net yang memungkinkan Anda mengirimkan a
DateTime
keDateTimeOffset
parameter atau variabel apa pun . Ketika melakukannya, yang.Kind
penting . Jika Anda melewati jenis UTC, itu akan dibawa dengan nol offset, tetapi jika Anda melewati salah satu.Local
atau.Unspecified
, itu akan dianggap sebagai lokal . Kerangka kerja ini pada dasarnya mengatakan, "Ya, Anda meminta saya untuk mengubah waktu kalender menjadi waktu instan, tetapi saya tidak tahu dari mana ini berasal, jadi saya hanya akan menggunakan kalender lokal." Ini adalah masalah besar jika Anda memuat yang tidak ditentukanDateTime
pada komputer dengan zona waktu yang berbeda. (IMHO - yang seharusnya melempar pengecualian - tetapi tidak.)Plug tak tahu malu:
Banyak orang telah berbagi dengan saya bahwa mereka menganggap analogi ini sangat berharga, jadi saya memasukkannya ke dalam kursus Pluralsight saya, Fundamental Date and Time . Anda akan menemukan langkah demi langkah langkah-langkah analogi kamera dalam modul kedua, "Konteks Konteks", dalam klip berjudul "Waktu Kalender vs. Waktu Instan".
sumber
DateTimeOffset
di C #, maka Anda harus bertahanDATETIMEOFFSET
di SQL Server.DATETIME2
atau hanyaDATETIME
(tergantung pada kisaran yang diperlukan) baik untukDateTime
nilai reguler . Ya - Anda dapat menyelesaikan waktu lokal dari pasangan zona waktu + dto atau utc. Perbedaannya adalah - apakah Anda selalu ingin menghitung aturan dengan setiap tekad, atau Anda ingin menghitungnya? Dalam banyak kasus (kadang-kadang karena masalah hukum) DTO adalah pilihan yang lebih baik.DateTimeOffset.Now
pada server, Anda memang akan mendapatkan offset server. Intinya adalah bahwaDateTimeOffset
jenis dapat mempertahankan offset itu. Anda bisa dengan mudah melakukan itu pada klien, mengirimkannya ke server, dan kemudian server Anda akan tahu offset klien.Dari Microsoft:
sumber: "Memilih Antara DateTime, DateTimeOffset, TimeSpan, dan TimeZoneInfo" , MSDN
Kami menggunakan
DateTimeOffset
hampir semua hal karena aplikasi kami berhubungan dengan titik waktu tertentu (misalnya ketika catatan dibuat / diperbarui). Sebagai catatan, kami juga menggunakanDATETIMEOFFSET
SQL Server 2008.Saya melihat
DateTime
berguna ketika Anda ingin berurusan dengan kencan saja, hanya kali, atau berurusan dengan baik dalam arti umum. Misalnya, jika Anda memiliki alarm yang Anda ingin pergi setiap hari pukul 7 pagi, Anda bisa menyimpan bahwa dalamDateTime
memanfaatkanDateTimeKind
dariUnspecified
karena Anda ingin pergi pada 7:00 terlepas dari DST. Tetapi jika Anda ingin merepresentasikan riwayat kejadian alarm, Anda akan menggunakannyaDateTimeOffset
.Berhati-hatilah saat menggunakan campuran
DateTimeOffset
danDateTime
terutama saat menetapkan dan membandingkan antara jenis. Selain itu, hanya bandingkanDateTime
instance yang samaDateTimeKind
karenaDateTime
mengabaikan offset zona waktu saat membandingkan.sumber
Kind
sama, perbandingan bisa saja salah. Jika kedua belah pihak memilikiDateTimeKind.Unspecified
Anda tidak benar-benar tahu bahwa mereka berasal dari zona waktu yang sama. Jika kedua belah pihakDateTimeKind.Local
, sebagian besar perbandingan akan baik-baik saja, tetapi Anda masih bisa memiliki kesalahan adalah satu sisi ambigu di zona waktu lokal. Benar-benar hanyaDateTimeKind.Utc
perbandingan yang sangat mudah, dan ya,DateTimeOffset
biasanya lebih disukai. (Ceria!)DateTime hanya mampu menyimpan dua waktu berbeda, waktu lokal dan UTC. The Kind properti yang menunjukkan.
DateTimeOffset memperluas ini dengan bisa menyimpan waktu lokal dari mana saja di dunia. Itu juga menyimpan offset antara waktu setempat dan UTC. Perhatikan bagaimana DateTime tidak dapat melakukan ini kecuali Anda menambahkan anggota tambahan ke kelas Anda untuk menyimpan offset UTC itu. Atau hanya pernah bekerja dengan UTC. Yang dengan sendirinya adalah ide yang bagus btw.
sumber
Ada beberapa tempat yang
DateTimeOffset
masuk akal. Salah satunya adalah ketika Anda berurusan dengan acara berulang dan waktu musim panas. Katakanlah saya ingin mengatur alarm untuk berbunyi jam 9 pagi setiap hari. Jika saya menggunakan aturan "store as UTC, display as time time", maka alarm akan berbunyi pada waktu yang berbeda ketika waktu musim panas berlaku.Mungkin ada yang lain, tetapi contoh di atas sebenarnya adalah salah satu yang pernah saya temui sebelumnya (ini sebelum penambahan
DateTimeOffset
BCL - solusi saya pada saat itu adalah secara eksplisit menyimpan waktu di zona waktu lokal, dan menyimpan informasi zona waktu di sampingnya: pada dasarnya apa yangDateTimeOffset
dilakukan secara internal).sumber
Perbedaan paling penting adalah bahwa DateTime tidak menyimpan informasi zona waktu, sedangkan DateTimeOffset tidak.
Meskipun DateTime membedakan antara UTC dan Lokal, sama sekali tidak ada offset zona waktu eksplisit yang terkait dengannya. Jika Anda melakukan serialisasi atau konversi apa pun, zona waktu server akan digunakan. Bahkan jika Anda secara manual membuat waktu lokal dengan menambahkan menit untuk mengimbangi waktu UTC, Anda masih bisa mendapatkan sedikit dalam langkah serialisasi, karena (karena kurangnya offset eksplisit di DateTime) itu akan menggunakan zona waktu server offset.
Misalnya, jika Anda membuat serialisasi nilai DateTime dengan Kind = Lokal menggunakan Json.Net dan format tanggal ISO, Anda akan mendapatkan string seperti
2015-08-05T07:00:00-04
. Perhatikan bahwa bagian terakhir (-04) tidak ada hubungannya dengan DateTime Anda atau offset apa pun yang Anda gunakan untuk menghitungnya ... itu hanya murni zona waktu server offset.Sementara itu, DateTimeOffset secara eksplisit menyertakan offset. Ini mungkin tidak termasuk nama zona waktu, tetapi setidaknya itu termasuk offset, dan jika Anda membuat serial, Anda akan mendapatkan offset yang dimasukkan secara eksplisit dalam nilai Anda alih-alih apa pun waktu lokal server yang terjadi.
sumber
The most important distinction is that DateTime does not store time zone information, while DateTimeOffset does.
Sepotong kode dari Microsoft ini menjelaskan semuanya:
sumber
Sebagian besar jawabannya baik, tetapi saya berpikir untuk menambahkan beberapa tautan MSDN untuk informasi lebih lanjut
sumber
Perbedaan utama adalah bahwa
DateTimeOffset
dapat digunakan bersamaan denganTimeZoneInfo
untuk mengkonversi ke waktu lokal di zona waktu selain yang saat ini.Ini berguna pada aplikasi server (misalnya ASP.NET) yang diakses oleh pengguna di zona waktu yang berbeda.
sumber
Satu-satunya sisi negatif dari DateTimeOffset yang saya lihat adalah Microsoft "lupa" (sesuai desain) untuk mendukungnya di kelas XmlSerializer mereka. Tetapi sejak itu telah ditambahkan ke kelas utilitas XmlConvert.
XmlConvert.ToDateTimeOffset
XmlConvert.ToString
Saya katakan maju dan gunakan DateTimeOffset dan TimeZoneInfo karena semua manfaatnya, berhati-hatilah saat membuat entitas yang akan atau mungkin diserialisasi ke atau dari XML (semua objek bisnis).
sumber