Bagaimana cara menangani TimeZone dengan benar di SQL Server?

34

Server pengembangan lokal saya di Timur Tengah, tetapi server produksi saya di Inggris.

Saya perlu menunjukkan tanggal kepada pengguna di zona waktu mereka. Misalnya, jika pengguna di Arab Saudi maka saya harus menunjukkan waktu sesuai dengan format Arab Saudi.

Haruskah saya membuat tabel database baru yang disebut TimeZone dan menghemat waktu dalam UTC?

pengguna960567
sumber
Secara efektif Mengubah tanggal antara waktu UTC dan Lokal (mis. PST) di SQL 2005 http://stackoverflow.com/questions/24797/effectively-converting-dates-between-utc-and-local-ie-pst-time-in- sql-2005
mehdi
Apakah ini aplikasi web, atau aplikasi desktop, atau ...? Bagaimana ini diterapkan sangat bervariasi oleh mekanisme pengiriman klien, karena apa yang Anda butuhkan tergantung pada sisi klien.
Jon Seigel
Web ini dan juga ponsel asli. Ya efek ini berbeda klien berbeda.
user960567
1
Sepertinya pertanyaan Anda bukan hanya tentang database itu sendiri, tetapi melibatkan pengembangan aplikasi juga. Pertanyaan Stack Overflow ini harus dibaca untuk Anda saat itu: Waktu musim panas dan praktik terbaik Timezone
Gan

Jawaban:

48

Sayangnya, tidak ada perbaikan cepat untuk ini. Internasionalisasi suatu aplikasi harus menjadi bagian dari diskusi desain pertama, karena hal itu benar-benar menjadi inti dari banyak bidang yang berbeda, termasuk perbandingan tanggal / waktu dan format keluaran.

Ngomong-ngomong, untuk melacak Doing It Right, penting untuk menyimpan informasi zona waktu bersama waktu . Dengan kata lain, menyadari bahwa tanggal / waktu tidak20130407 14:50 ada artinya tanpa (a) termasuk offset UTC saat itu zona waktu (catatan 1) , atau (b) memastikan bahwa semua logika yang memasukkan nilai-nilai ini pertama kali dikonversi ke offset tetap tertentu ( kemungkinan besar 0). Tanpa salah satu dari hal-hal itu, dua nilai waktu yang diberikan tidak dapat dibandingkan, dan datanya rusak . (Metode terakhir bermain dengan api (catatan 2) , omong-omong; jangan lakukan itu.)

Di SQL Server 2008+, Anda dapat menyimpan offset dengan waktu secara langsung dengan menggunakan datetimeoffsettipe data. (Untuk kelengkapan, pada 2005 dan sebelumnya, saya akan menambahkan kolom kedua untuk menyimpan nilai offset UTC saat itu (dalam menit).)

Ini memudahkan aplikasi jenis desktop, karena platform ini biasanya memiliki mekanisme untuk secara otomatis mengkonversi tanggal / waktu + zona waktu ke waktu lokal dan kemudian memformat untuk output, semua berdasarkan pada pengaturan regional pengguna.

Untuk web, yang merupakan arsitektur yang terputus secara inheren, bahkan dengan data back-end yang diatur dengan benar, itu lebih kompleks karena Anda memerlukan informasi tentang klien untuk dapat melakukan konversi dan / atau pemformatan. Ini biasanya dilakukan melalui pengaturan preferensi pengguna (aplikasi mengkonversi / memformat hal-hal sebelum output), atau hanya menampilkan hal-hal dengan format tetap yang sama dan offset zona waktu untuk semua orang (yang dilakukan oleh platform Stack Exchange saat ini).

Anda dapat melihat bagaimana jika data back-end tidak diatur dengan benar, sangat cepat itu akan menjadi rumit dan meretas. Saya tidak akan merekomendasikan salah satu dari jalan-jalan tersebut karena Anda hanya akan berakhir dengan lebih banyak masalah di telepon.

Catatan 1:

Offset UTC zona waktu tidak tetap: pertimbangkan penghematan siang hari di mana offset UTC zona bervariasi dengan plus atau minus satu jam. Juga tanggal penghematan siang hari zona bervariasi secara teratur. Jadi menggunakan datetimeoffset(atau gabungan dari local timedan UTC offset at that time) menghasilkan pemulihan informasi maksimum.

Catatan 2:

Ini tentang mengendalikan input data. Meskipun tidak ada cara yang mudah untuk memvalidasi nilai yang masuk, lebih baik untuk menegakkan standar sederhana yang tidak melibatkan perhitungan. Jika API publik mengharapkan tipe data yang menyertakan offset, persyaratan itu akan jelas bagi pemanggil.

Jika bukan itu masalahnya, penelepon harus bergantung pada dokumentasi (jika mereka membacanya), atau perhitungannya dilakukan secara tidak benar, dll. Ada lebih sedikit mode kegagalan / bug saat memerlukan offset, khususnya untuk sistem terdistribusi ( atau bahkan hanya web / database pada server terpisah seperti yang terjadi di sini).

Menyimpan offset tetap membunuh dua burung dengan satu batu; dan bahkan jika itu tidak diperlukan sekarang , itu membuat kemungkinan tersedia nanti jika perlu. Benar itu membutuhkan lebih banyak penyimpanan, tapi saya pikir itu layak trade-off karena data hilang jika tidak pernah direkam sejak awal.

Jon Seigel
sumber
3
Seperti yang saya pahami, offset tidak sama dengan zona waktu ... waktu yang disimpan dalam datetimeoffset kehilangan informasi seperti kesadaran waktu musim panas ... info lebih lanjut: stackoverflow.com/tags/timezone/info
Peter McEvoy
1
@PeterMcEvoy DST tidak memiliki relevansi di sini. datetimeoffsetberarti "ini adalah waktu setempat pengguna / komputer ketika hal itu terjadi" - kita tidak perlu tahu apakah DST berlaku atau tidak, karena offset UTC yang diberikan selalu ada (tertanam dalam datetimeoffsetnilai).
Dai
12

Saya telah mengembangkan solusi komprehensif untuk konversi zona waktu di SQL Server. Lihat Dukungan Zona Waktu SQL Server di GitHub .

Itu benar menangani konversi antara zona waktu, dan ke dan dari UTC, termasuk waktu musim panas.

Ini serupa dalam konsep dengan solusi "T-SQL Toolbox" yang dijelaskan dalam jawaban iklan, tetapi menggunakan zona waktu IANA / Olson / TZDB yang lebih umum daripada Microsoft, dan itu mencakup utilitas untuk menjaga data tetap dipertahankan sebagai rilis baru dari TZDB keluar.

Contoh penggunaan (untuk menjawab OP):

SELECT Tzdb.UtcToLocal(sysutcdatetime(), 'Asia/Riyadh') as CurrentTimeInSaudiArabia

Lihat readme di GitHub untuk API tambahan dan penjelasan terperinci.

Juga, perhatikan bahwa karena ini adalah solusi berbasis UDF, itu tidak dirancang dengan kinerja sebagai tujuan utama. Masih akan lebih baik jika fungsi ini dibangun ke SQL Server, mirip dengan bagaimana CONVERT_TZfungsi itu ada di Oracle dan MySQL.

Matt Johnson-Pint
sumber
6

SQL Server membuat modifikasi pada 2005 dan seterusnya di mana zona waktu internal disimpan dalam UTC. Ini sebagian besar disebabkan oleh replikasi-geo dan proyektor HA yang melibatkan pengiriman log, dan menghemat waktu pengiriman log di zona waktu yang berbeda membuat metode lama tidak dapat mengembalikannya.

Dengan demikian, menyimpan segala sesuatu secara internal dalam waktu UTC memungkinkan SQL Server berfungsi dengan baik secara global. Ini adalah salah satu alasan mengapa penghematan siang hari adalah jenis yang menyusahkan untuk ditangani di Windows, karena produk MS lainnya seperti Outlook juga menyimpan tanggal / waktu secara internal sebagai UTC dan membuat offset yang perlu ditambal.

Saya bekerja di sebuah perusahaan di mana kami memiliki ribuan server (bukan MS SQL Server, tetapi semua jenis server) tersebar di seluruh dunia, dan jika kami tidak secara spesifik memaksa semuanya untuk pergi dengan UTC, kami semua akan menjadi gila sangat cepat.

Ali Razeghi
sumber
5

Saya telah mengembangkan dan menerbitkan proyek "T-SQL Toolbox" pada codeplex untuk membantu siapa saja yang berjuang dengan penanganan waktu dan zona waktu di SQL Server. Ini open source dan sepenuhnya gratis untuk digunakan.

Ini menawarkan UDFs konversi datetime mudah menggunakan T-SQL biasa dengan tabel konfigurasi tambahan di luar kotak.

Dalam contoh Anda, Anda dapat menggunakan sampel berikut:

SELECT [DateTimeUtil].[UDF_ConvertLocalToLocalByTimezoneIdentifier] (
    'GMT Standard Time', -- the original timezone in which your datetime is stored
    'Middle East Standard Time', -- the target timezone for your user
    '2014-03-30 01:55:00' -- the original datetime you want to convert
)

Ini akan mengembalikan nilai datetime yang dikonversi untuk pengguna Anda.

Daftar semua zona waktu yang didukung dapat ditemukan dalam tabel "DateTimeUtil.Timezone" juga disediakan dalam database T-SQL Toolbox.

iklan
sumber
Toolkit semacam itu tampaknya akan sangat membantu pengembang. Namun, fungsi skalar adalah kotak hitam untuk pengoptimal kueri. Itu berarti bahwa ketika saya menerapkan fungsi Anda ke kolom, tabel konfigurasi yang Anda sebutkan akan dipukul sebanyak yang ada di baris yang ditetapkan hasil (dengan asumsi saya menggunakan fungsi dalam klausa SELECT saja). Itu tampaknya bukan perspektif yang baik dalam hal kinerja. Saya belum benar-benar menguji perangkat Anda, jadi saya tidak bisa mengatakan dengan pasti, itu hanya masalah umum berdasarkan apa yang saya ketahui.
Andriy M
Andriy, tentu saja, Anda benar dari sudut pandang kinerja. Tabel permintaan UDF tidak dirancang untuk operasi data massal, tetapi untuk penggunaan yang mudah. Namun demikian, mereka melakukan cukup baik hingga sekitar 100.000 catatan di komputer saya.
ADS
2
Jika seseorang harus memproses lebih banyak catatan dalam kasus penggunaannya, dan hal-hal kinerja, Anda sebaiknya memikirkan untuk mempertahankan data yang sudah dihitung sebelumnya. Tetapi bahkan kemudian, UDF ini mungkin membantu untuk mempertahankan nilai-nilai datatime di zona waktu yang diperlukan.
ADS
Dari sudut pandang saya masalah ini bukan tentang kinerja, dan lebih lanjut tentang hanya mendapatkan fungsi dasar di sana. Untuk dapat mengembalikan informasi yang akurat dari permintaan adalah hal pertama. Mengerjakan beberapa tabel temp untuk men-cache hal-hal dan kemudian merujuk ke hal itu dalam kueri atau bagaimana pun Anda menanganinya untuk meningkatkan kinerja menjadi hal sekunder.
Aksi Dan
1

Saya mungkin kehilangan sesuatu yang jelas, tetapi jika semua yang Anda ingin lakukan adalah menampilkan tanggal menggunakan zona waktu pengguna dan format bahasa, cara paling sederhana adalah dengan selalu menyimpan tanggal dalam UTC dalam database dan membiarkan aplikasi klien mengkonversi dari UTC ke lokal zona waktu dan gunakan pengaturan regional pengguna untuk memformat tanggal sesuai.

20c
sumber