SQL Server'da TimeZone düzgün bir şekilde nasıl kullanılır?


34

Yerel geliştirme sunucum Orta Doğu’da, ancak üretim sunucum İngiltere’de.

Kullanıcıya kendi saat dilimindeki tarihi göstermem gerekiyor. Örneğin, bir kullanıcı Suudi Arabistan'da ise, zamanı Suudi Arabistan formatına göre göstermem gerekiyor.

TimeZone adlı yeni bir veritabanı tablosu oluşturup, UTC'ye kaydetmem gerekir mi?


Etkili UTC ve Yerel SQL 2005'te (yani. PST) saat arasındaki tarihleri dönüştürme http://stackoverflow.com/questions/24797/effectively-converting-dates-between-utc-and-local-ie-pst-time-in- sql-2005
mehdi

Bu bir web uygulaması mı, yoksa masaüstü uygulaması mı yoksa ...? Bunun nasıl uygulandığı müşteri teslimat mekanizmasına göre büyük ölçüde değişiklik gösterir, çünkü ihtiyacınız olan müşteri tarafına bağlıdır.
Jon Seigel

Bu web gibi yerli mobil. Evet bu farklı müşterileri farklı şekilde etkiler.
user960567

1
Sorunuz sadece veritabanının kendisi ile ilgili değil aynı zamanda uygulama geliştirmeyi de içeriyor. Bu Yığın Taşması sorusu sizin için mutlaka okunması gereken bir soru: Yaz saati uygulaması ve en iyi zaman dilimi uygulamaları
Gan

Yanıtlar:


48

Maalesef bunun için hızlı bir düzeltme yok. Bir uygulamanın uluslararasılaştırılması, tarih / saat karşılaştırmaları ve çıktı formatlama da dahil olmak üzere birçok farklı alanın çekirdeğine gittiği için ilk tasarım tartışmalarının bir parçası olmalıdır.

Her neyse, Doğru Yapmanın izini sürmek için, saat dilimi bilgilerini zamanla birlikte depolamak çok önemlidir . Başka bir deyişle, tarih / saatin (a) saat diliminin o zamanki UTC ofsetini (not 1) dahil olmak üzere (a) ya da (b) bu ​​değerleri yerleştiren tüm mantıkların belirli bir sabit ofsete dönüştürülmesini sağlayarak (b) olmadan anlamsız20130407 14:50 olduğunu anlamak büyük olasılıkla 0). Bunlardan hiçbiri olmadan, verilen iki zaman değeri karşılaştırılamaz ve veriler bozulmuştur . (Sonuncusu bu arada ateşle oynuyor (not 2) , bu arada; bunu yapma.)

SQL Server 2008+ 'de, datetimeoffsetveri türünü kullanarak ofseti zamanla doğrudan saklayabilirsiniz . (2005 yılında ve öncesinde tamamlama için, geçerli UTC ofset değerini saklamak için ikinci bir sütun eklerdim (dakika cinsinden).)

Bu, masaüstü tipi bir uygulama için kolaylaştırır, çünkü bu platformlar normalde bir tarih / saat + saat dilimini yerel bir saate otomatik olarak dönüştürme ve daha sonra hepsi bölgesel ayarları temel alarak çıktı için formatlama mekanizmalarına sahiptir.

Doğal olarak bağlantısı kesilmiş bir mimari olan web için, arka uç verileri düzgün bir şekilde ayarlanmış olsa bile, daha karmaşıktır, çünkü müşteriyi dönüştürme ve / veya biçimlendirmeyi yapabilmek için bilgiye ihtiyacınız vardır. Bu genellikle kullanıcı tercihi ayarları (uygulama çıktıdan önce işleri dönüştürür / biçimlendirir) veya sadece herkes için (Stack Exchange platformunun şu anda yaptığı gibi) aynı sabit format ve saat dilimi uzaklığına sahip olanları göstererek yapılır.

Arka uç verilerinin doğru bir şekilde kurulmadığını, çok hızlı bir şekilde karmaşık ve rahatsız edici hale geleceğini görebilirsiniz. Bu yollardan hiçbirine gitmenizi tavsiye etmem çünkü satır sonunda daha fazla sorunla karşılaşacaksınız.

Not 1:

Bir saat diliminin UTC kayması sabit değil: bir bölgenin UTC kaymasının bir saat artı ya da eksi değiştiği gün ışığından yararlanma koşullarını göz önünde bulundurun. Ayrıca bölgelerin günışığı tasarruf tarihleri ​​düzenli olarak değişmektedir. Kullanarak Yani datetimeoffset(veya kompozit local timeve UTC offset at that time) maksimum bilgi kurtarma sonuçlanır.

Not 2:

Veri girişlerini kontrol etmekle ilgili. Gelen değerleri doğrulamanın güvenilir bir yolu olmasa da, hesaplamaları içermeyen basit bir standardın uygulanması daha iyidir. Genel bir API ofset içeren bir veri türü beklerse, bu gereksinim arayan kişiye açık olacaktır.

Öyle olmadıysa, arayan kişi belgelere güvenmek zorundadır (eğer okursa) veya hesaplama yanlış yapılır, vs. vb., Özellikle dağıtılmış bir sistem için mahsup talep edildiğinde daha az hata / hata modu vardır ( ve hatta burada olduğu gibi ayrı sunucularda sadece web / veritabanı).

Dengelemeyi yine de saklamak iki taşı bir taşla öldürür; gerektiriyordu olmasa bile ve şimdi , bu gerekirse daha sonra olasılık kullanılabilir hale getirir. Doğru, daha fazla depolama alanı kaplıyor, ancak bence takas etmeye değer çünkü bence ilk etapta kaydedilmemişse veriler kayboluyor.


3
Anladığım kadarıyla bir mahsup, saat dilimi ile aynı değildir ... tarihçede saklanan zamanlar, gün ışığından yararlanma saati farkındalığı gibi bilgileri kaybeder ... Daha fazla bilgi: stackoverflow.com/tags/timezone/info
Peter McEvoy

1
@PeterMcEvoy DST'nin burada bir önemi yoktur. datetimeoffset"Bu, olay gerçekleştiğinde kullanıcının / bilgisayarın yerel zamanıdır" - DST'nin etkin olup olmadığını bilmemize gerek yoktur, çünkü verilen UTC ofseti her zaman oradadır ( datetimeoffsetdeğerin içine gömülüdür ).
Dai

12

SQL Server'da saat dilimi dönüştürmesi için kapsamlı bir çözüm geliştirdim. GitHub'da bkz. SQL Server Saat Dilimi Desteği .

Saat dilimleri arasındaki ve gün ışığından yararlanma saati de dahil olmak üzere UTC'den dönüşüme doğru şekilde işler.

Konsept olarak adss'in cevabında açıklanan "T-SQL Araç Kutusu" çözümüne benzer, ancak Microsoft'un yerine daha yaygın olan IANA / Olson / TZDB zaman dilimlerini kullanır ve verilerin yeni sürümler olarak tutulması için yardımcı programlar içerir. TZDB çıktı.

Örnek kullanım (OP'ye cevap vermek için):

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

Ek API'ler ve ayrıntılı açıklama için GitHub'daki benioku dosyasına bakın .

Ayrıca, bunun UDF tabanlı bir çözüm olduğu için birincil amaç olarak performansla tasarlanmadığını unutmayın. CONVERT_TZOracle ve MySQL'de işlevin varlığına benzer şekilde, bu işlevsellik SQL Server'da yerleşik olsaydı hala daha iyi olurdu .


6

SQL Server, 2005’te dahili zaman diliminin UTC’de kaydedildiği yerlerde değişiklikler yaptı. Bu, büyük ölçüde jeo-replikasyon ve kütük nakliyesi içeren HA projektörleri nedeniyle ve kütük nakliyesi zamanlarının farklı zaman dilimlerinde kaydedilmesi eski yöntemin onları geri kazanmasını imkansız hale getirdi.

Böylece, her şeyi UTC zamanında dahili olarak kaydetmek, SQL Server'ın global olarak iyi çalışmasına izin verdi. Bu, gün ışığından yararlanma tasarruflarının Windows'ta başa çıkmak için bir sıkıntı olmasının nedenlerinden biridir, çünkü Outlook gibi diğer MS ürünleri de tarih / saati dahili olarak UTC olarak kaydeder ve yamalanması gereken bir ofset oluşturur.

Tüm dünyaya yayılmış binlerce sunucumuz (MS SQL Sunucuları olmasa da her türlü sunucuların bulunduğu) bir şirkette çalışıyorum ve UTC'ye gitmek için her şeyi özel olarak zorlamazsak, hepimiz çıldırırız. çok çabuk.


5

SQL Server'da tarih ve saat dilimi ile mücadele eden herkese yardımcı olmak için kodeksi üzerine “T-SQL Toolbox” projesini geliştirdim ve yayınladım . Açık kaynak ve kullanımı tamamen ücretsizdir.

Kutudan çıkarılan ek yapılandırma tabloları ile sade T-SQL kullanarak kolay tarih / saat dönüşümü UDF'leri sunar.

Örnekte, aşağıdaki örneği kullanabilirsiniz:

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
)

Bu, kullanıcı için dönüştürülen tarih saat değerini döndürür.

Desteklenen tüm zaman dilimlerinin bir listesi T-SQL Araç Kutusu veritabanında da verilen "DateTimeUtil.Timezone" tablosunda bulunabilir.


Böyle bir araç takımı, geliştirici için çok yardımcı olacak gibi görünüyor. Bununla birlikte, skalar bir işlev, sorgu iyileştiricinin kara kutusudur. Bu, fonksiyonunuzu bir sütuna uyguladığımda, bahsettiğiniz konfigürasyon tablolarının sonuç kümesindeki satır sayısı kadar çarpacağı anlamına gelir (fonksiyonu yalnızca SELECT yan tümcesinde kullandığımı varsayarak). Bu performans açısından hoş bir bakış açısı gibi görünmüyor. Yine de araç setinizi henüz test etmedim, bu yüzden kesin olarak söyleyemem, bu sadece bildiklerime dayanan genel bir endişe.
Andriy M,

Andriy, elbette, performans perspektifinden haklısın. UDF sorgu tabloları toplu veri işlemleri için değil, kolay kullanım için tasarlanmıştır. Yine de, makinemde yaklaşık 100.000 kayıt tutuyorlar.
adss

2
Birinin kullanım durumunda daha fazla kayıt işlemesi gerekiyorsa ve performans önemlidir, önceden hesaplanmış verileri sürdürmeyi daha iyi düşünmelisiniz. Ancak o zaman bile, bu UDF'ler veri zaman değerlerini istenen zaman dilimlerinde sürdürmeye yardımcı olabilir.
adss

Benim açımdan bu sorun performansla ilgili değil, sadece temel işlevselliği elde etmekle de ilgili. Bir sorgudan doğru bilgi döndürmek ilk şeydir. Bazı şeyleri önbelleğe almak için geçici bir tabloyu çalışmadan sonra sorguya bakın ya da performansı iyileştirmek için onu kullanın ancak ikincil gelir.
Eylem Dan

1

Açıkça net bir şey eksik olabilir, ancak yapmak istediğiniz tek şey kullanıcı saat dilimi ve dil biçimini kullanarak tarihi göstermekse, en basit yöntem, tarihleri ​​UTC'de her zaman veritabanında depolamak ve istemci uygulamasının UTC'den yerel veriye dönüştürmesini sağlamaktır. saat dilimini ve tarihi buna göre biçimlendirmek için kullanıcının bölgesel ayarlarını kullanın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.