Praktik terbaik untuk menyimpan DateTime berdasarkan TimeZone

16

Mengembangkan aplikasi web yang memungkinkan Pengguna menjadwalkan janji temu berdasarkan TimeZone mereka. Dan saya menyimpan datetime yang dijadwalkan Pengguna sebagai datetime server ke dalam bidang basis data. Sementara menampilkan informasi jadwal mengambil nilai dari Database dan diubah menjadi timzone pengguna. memproses dalam basis kode Saya mengonversi DateTime berdasarkan zona waktu pengguna. Tolong sarankan apakah ini praktik terbaik atau ada cara mudah ada?

pengguna46506
sumber

Jawaban:

33

Selamat datang di salah satu masalah tersulit dalam pemrograman non-komputasi - yang mewakili tanggal dan waktu dengan tepat untuk pengguna akhir.

Secara realistis, stempel waktu harus disimpan dalam representasi tunggal yang tetap terlepas dari bagaimana interpretasinya, karena tidak peduli seberapa keras Anda mencoba, Anda akan selalu memiliki kasus yang ambigu, dan Anda tidak dapat menyelesaikannya tanpa representasi tetap. Dan Anda telah memilih salah satu dari kasus penggunaan terburuk - menjadwalkan janji temu. Satu-satunya kasus penggunaan umum yang lebih buruk adalah perjalanan udara, di mana perjalanan mungkin dimulai di satu zona waktu dan berakhir di zona waktu lain, mungkin pada waktu setempat yang lebih awal.

Selalu, selalu, SELALU menyimpan dalam UTC dan ditampilkan di zona waktu yang dipilih atau ditentukan pengguna. Jika memungkinkan, buat pengguna memberi tahu Anda tentang zona waktu yang mereka yakini sebagai timestamp ketika mereka memasukkannya ( misalnya , memiliki bidang zona waktu yang jelas dan mengisinya dengan zona pilihan mereka).

Ross Patterson
sumber
1
+1. Dan itu fleksibel. Memiliki waktu referensi standar umum, konsisten, universal - setiap zona lokal "dereferencing" akan dilakukan dengan benar.
radarbob
Sebenarnya, menjadwalkan janji temu adalah salah satu dari beberapa kali ketika Anda mungkin tidak menyimpannya sebagai UTC: Jika aturan DST berubah (atau offset dari UTC), apa yang terjadi dengan waktu janji temu? Dalam kebanyakan kasus, Anda ingin waktu janji temu tetap sama secara lokal, yang berarti nilai UTC berubah. Anda kemungkinan besar ingin menyimpan nilai yang mewakili "TimeInTimeZone + TimeZone", yang darinya Anda dapat memperoleh UTC dengan mudah. Penjadwalan lintas zona waktu (seperti maskapai penerbangan) memiliki kendala yang mungkin berarti kombinasi keduanya digunakan.
Clockwork-Muse
1
Oh, lebih buruk dari itu. Saya secara teratur mengadakan pertemuan dengan kolega di negara lain yang aturan perubahan waktunya berbeda dengan saya. Ketika itu terjadi, apa jawaban yang benar? Sebenarnya, tidak ada komputer yang tahu :-(
Ross Patterson
3

Cara termudah untuk menangani informasi tanggal / waktu tergantung pada persyaratan aplikasi Anda.

Jika tanggal dan waktu dimasukkan oleh pengguna dan server tidak memproses dengan informasi tanggal / waktu itu kecuali untuk menyimpannya dalam database dan tidak ada harapan bahwa waktu yang dimasukkan akan disesuaikan dengan lokasi di mana ia dilihat (misalnya , pengguna memasukkan "8:00 PM" dan itu harus ditampilkan sebagai "8:00 PM" di mana pun di dunia itu dilihat), maka cara termudah adalah dengan menyimpan DateTime sebagai waktu lokal tanpa informasi zona waktu.

Di sisi lain, jika server harus menggunakan DateTime yang dimasukkan sebagai pemicu untuk melakukan sesuatu, atau jika waktu harus disesuaikan dengan zona waktu saat ini, maka pilihan terbaik Anda adalah menyimpan DateTime sebagai waktu UTC dan menyesuaikannya dengan lokal waktu (untuk lokasi pengguna saat ini) setiap kali Anda membacanya dari database.

Bart van Ingen Schenau
sumber
-1 untuk "simpan dalam waktu lokal", +1 untuk "simpan dalam UTC".
Ross Patterson
@RossPatterson: Bisakah Anda menjelaskan '-1 untuk "simpan di waktu setempat"'? Saya ingin tahu mengapa itu harus menjadi ide yang buruk, mengingat kondisi yang saya berikan dengannya.
Bart van Ingen Schenau
1
Misalnya, menggunakan waktu pengguna-lokal berarti bahwa setiap nilai secara efektif adalah satu dari beberapa lusin tipe data yang berbeda. Yang berarti Anda tidak dapat melakukan operasi basis data yang menarik seperti "TIMESTAMP> '2013-08-27T12: 00: 00'". Itu bahkan berarti Anda tidak bisa tahu kapan dan apakah akan menerapkan konversi Daylight Saving Time.
Ross Patterson
@RossPatterson: Terima kasih. Saya setuju bahwa waktu setempat bukan solusi yang tepat dalam banyak kasus.
Bart van Ingen Schenau
2

Adalah penting bahwa Anda tidak mengacaukan dua konsep terkait.

Jika Anda memanipulasi titik waktu aktual, yaitu waktu tertentu pada hari tertentu, maka satu-satunya cara untuk melakukannya adalah dengan selalu menggunakan nilai waktu UTC universal. Jangan pernah mencoba menyimpan ini sebagai nilai yang relevan dengan zona waktu. Saat menampilkan nilai waktu ini ke pengguna, selalu konversikan ke zona waktu pengguna pada waktu itu. (Dan jangan lupa waktu dan tanggal tergantung pada zona waktu.)

Konsep lainnya adalah "ekspresi waktu" seperti "8:00 setiap hari Selasa". Anda secara khusus menyebutkan mengizinkan orang untuk menjadwalkan janji temu, dan jika Anda memiliki janji temu berulang, Anda perlu ungkapan seperti itu. Saya tidak tahu bahasa ekspresi standar apa pun, tetapi apa pun yang Anda gunakan, itu akan relatif terhadap zona waktu orang yang menentukannya. Akan lebih baik untuk membuat ini eksplisit misalnya "8:00 PM setiap hari Selasa di Zona Waktu Pasifik". Dalam kasus ekspresi waktu, Anda menyimpan ini selalu sebagai string, dan tidak pernah melibatkan format waktu sistem apa pun.

Lihat lebih banyak diskusi tentang ini di blog saya

AgilePro
sumber
1

Banyak jawaban di sini menunjukkan penyimpanan sebagai UTC. Tapi berhati-hatilah dengan ini. Misalnya, jika Anda menjadwalkan janji temu pada pukul 12:00 tetapi janji temu dilakukan setelah perubahan waktu musim panas, apa yang akan terjadi? UTC tidak menyimpan informasi apakah dst aktif ketika janji temu disimpan. Banyak sistem besar dan terkenal telah membuat kesalahan ini, di mana pengguna mengirim email pada jam 9 pagi di musim panas, dan kemudian di musim dingin waktu yang dikirim menunjukkan jam 8 pagi, karena perhitungan kembali dari UTC tergantung pada saat Anda melihat datetime, tidak aktif saat datetime direkam.

Jauh lebih baik dengan menganggap pengguna Anda ingin memiliki waktu yang ia pilih selalu. Tidak ada konversi UTC, tidak ada konversi waktu, tidak ada info zona waktu, tidak ada. Membuat janji dari 08: 00-12: 00 pada 21 Maret 2016 hanya itu. Jangan gunakan waktu lokal atau waktu UTC, tetapi waktu yang tidak ditentukan (di json ini tidak memiliki z atau +, pada dasarnya, dalam. NET ini memiliki DateTime.Kind = DateTimeKind.Unspecified).

Tentu saja, jika kasus penggunaan Anda adalah bahwa Anda adalah perusahaan yang mengadakan pertemuan dengan seseorang dari zona waktu yang berbeda dan Anda ingin melihat informasi ini di, katakanlah, kalender perusahaan, tetapi memungkinkan pengguna untuk melihat waktu apa yang ada di zona waktu mereka, itu menjadi lebih rumit. Waktu harus tepat untuk orang yang berbeda di zona waktu yang berbeda (pemasok dan pelanggan).

Dalam kasus tersebut, Anda bahkan mungkin ingin mencatat kapan janji temu disimpan ke basis data, di zona waktu apa dan apakah itu termasuk dst atau tidak. Dengan begitu, Anda selalu dapat menghitung kembali waktu setempat untuk hal lain, baik untuk apa sekarang atau untuk apa yang dimaksudkan secara historis. Karena zona waktu sangat tidak statis, membuat segalanya semakin rumit.

Untungnya, di sinilah perpustakaan seperti http://nodatime.org/ masuk dan sangat direkomendasikan. Mereka bekerja dengan kencan jauh lebih konsisten. Bahkan kemudian saya akan merekomendasikan membungkus semua variabel dan logika datetime Anda dalam pembungkus Anda sendiri, menggunakan antarmuka sehingga mereka dapat diejek, dan kemudian Anda masih dapat beralih logika nanti.

Arwin
sumber
Saya tidak terlalu setuju dengan kesimpulan Anda, tetapi pertemuan pada siang hari yang dijadwalkan untuk perubahan tabungan siang hari adalah tantangan khusus, seperti pertemuan mingguan di siang hari yang dipesan beberapa tahun ke depan.
Bent
" Tentu saja, jika kasus penggunaan Anda adalah bahwa Anda adalah perusahaan yang mengadakan pertemuan dengan seseorang dari zona waktu yang berbeda dan Anda ingin melihat informasi ini dalam, katakanlah, kalender perusahaan, tetapi memungkinkan pengguna untuk melihat waktu apa yang ada di zona waktu mereka, semakin rumit. "- itu hampir semua perusahaan. Sangat sedikit perusahaan di luar China dan India yang dapat mengabaikan janji lintas zona waktu.
Ross Patterson
" Dengan begitu, Anda selalu dapat menghitung kembali waktu setempat untuk hal lain, baik untuk apa yang sekarang atau apa yang dimaksudkan untuk menjadi historis. Karena zona waktu sangat tidak statis, membuat segalanya semakin rumit. " - dulu Anda menerima bahwa Anda akan membuat perhitungan, Anda benar - benar perlu memilih satu representasi untuk waktu. UTC, EST (tetapi bukan EST5EDT), IST, apa pun. Tetapi Anda tidak bisa memiliki nilai berdasarkan beberapa zona waktu di bidang yang sama dan melakukan pemrosesan agregat yang sah pada mereka. Pemrosesan display, tentu saja. Tapi itu bagian yang mudah.
Ross Patterson
Setidaknya Anda masih dapat, dengan benar, mengkonversi ke UTC. Anda selalu dapat membuat tabel perhitungan atau nilai dari informasi ini dalam retrospeksi. Tapi Anda tidak pernah bisa pergi ke arah lain. Perhatikan bahwa SQL 2016 mulai mendukung ini secara asli, meskipun sayangnya masih bergantung pada - setidaknya secara historis - data registri tidak cukup benar - tetapi ini merupakan perbaikan lain.
Arwin