DateTime'ı TimeZone'a göre depolamak için en iyi uygulama


16

Kullanıcının TimeZone'larına göre randevu almasına izin verecek bir web uygulaması geliştirmek. Ve kullanıcı zamanlanan datetime sunucu datetime veritabanı alanına depolamak. Zamanlama bilgilerini gösterirken değeri Veritabanı'ndan aldı ve kullanıcı saat dilimine dönüştürüldü. Kod tabanı işleme DateTime kullanıcı saat dilimi dayalı dönüştürüyorum. Lütfen bu en iyi uygulama olup olmadığını veya herhangi bir kolay yolun mevcut olduğunu düşünün.

Yanıtlar:


33

Hesaplamalı olmayan programlamanın en zor sorunlarından birine hoş geldiniz - son kullanıcılara tarih ve saatleri düzgün bir şekilde temsil eder.

Gerçekçi olarak, zaman damgaları nasıl yorumlanacağına bakılmaksızın sabit bir tek gösterimde saklanmalıdır, çünkü ne kadar zor denerseniz deneyin, her zaman belirsiz durumlar olur ve bunları sabit bir temsil olmadan çözemezsiniz. Ve kullanım durumlarının en kötülerinden birini seçtiniz - randevu planlama. En kötü ortak kullanım durumu, bir seyahatin bir saat diliminde başlayıp başka bir saatte sona erebileceği, daha erken bir yerel saatte mümkün olabileceği hava yolculuğudur.

Her zaman, her zaman, HER ZAMAN UTC'de saklanır ve kullanıcının tercih ettiği veya açıkça belirtilen saat diliminde görüntülenir. Mümkünse, kullanıcıyı size zaman damgasının girdiğinde hangi zaman dilimine inandığını söylemesini sağlayın ( örneğin , açık bir saat dilimi alanına sahip olun ve tercih edilen bölgesi ile önceden doldurun).


1
+1. Ve esnek. Ortak, tutarlı, evrensel bir standart referans süresine sahip olmak - herhangi bir yerel bölge "dereferencing" doğru şekilde yapılacaktır.
radarbob

Aslında, randevu zamanlama sen belki birkaç kez biridir değil UTC olarak saklayın: DST kuralları değiştirmek (veya UTC offset) ne randevu zaman bir şey olursa? Çoğu durumda, randevu zamanının yerel olarak aynı kalmasını istersiniz, yani UTC değeri değişir. Büyük olasılıkla "TimeInTimeZone + TimeZone" ifadesini temsil eden ve UTC'yi kolayca türetebileceğiniz bir değer saklamak istersiniz. Çapraz zaman dilimi zamanlaması (havayolları gibi) muhtemelen her ikisinin de bir arada kullanılması anlamına gelen kısıtlamalara sahiptir.
Clockwork-Muse

1
Oh, bundan daha kötüye gidiyor. Diğer ülkelerdeki zaman değişikliği kuralları benimkinden farklı meslektaşlarımla düzenli olarak toplantılarım var. Bu olduğunda, doğru cevap nedir? Aslında, hiçbir bilgisayar bilemez :-(
Ross Patterson

3

Tarih / saat bilgisiyle başa çıkmanın en kolay yolu başvurunuzun gereksinimlerine bağlıdır.

Tarih ve saat kullanıcı tarafından girilirse ve sunucu bu tarih / saat bilgisiyle veritabanında saklamak dışında işlem yapmazsa ve girilen zamanın görüntülendiği konuma uyarlanması beklentisi yoksa (örneğin, , kullanıcı "20:00" değerini girmiştir ve dünyanın neresinde görüntülendiğine bakılmaksızın "20:00" olarak görüntülenmelidir), en kolay yol DateTime'ı saat dilimi bilgisi olmadan yerel saat olarak depolamaktır.

Öte yandan, sunucunun bir şey yapmak için girilen DateTime'ı tetikleyici olarak kullanması gerekiyorsa veya saatin geçerli saat dilimine doğru ayarlanması gerekiyorsa, en iyi seçeneğiniz DateTime'ı UTC saati olarak depolamak ve yerel olarak ayarlamaktır. veritabanından her okuduğunuzda saat (kullanıcının geçerli konumu için).


"Yerel saatte sakla" için -1, "UTC'de sakla" için +1.
Ross Patterson

@RossPatterson: "-1'i" yerel saatte sakla "için açıklayabilir misiniz? Onunla verdiğim koşullar göz önüne alındığında, bunun neden kötü bir fikir olması gerektiğini merak ediyorum.
Bart van Ingen Schenau

1
Örneğin, kullanıcının yerel saatini kullanmak, her değerin etkili bir şekilde birkaç düzine farklı veri türünden biri olduğu anlamına gelir. Bu, "TIMESTAMP> '2013-08-27T12: 00: 00'" gibi veritabanı işlemlerini ilginç bir şekilde gerçekleştiremeyeceğiniz anlamına gelir. Yaz Saati Uygulaması dönüşümlerinin ne zaman ve uygulanacağını bile bilemeyeceğiniz anlamına gelir.
Ross Patterson

@RossPatterson: Teşekkürler. Yerel saatin çoğu durumda doğru çözüm olmadığını kabul ediyorum.
Bart van Ingen Schenau

2

İlişkili iki kavramı birleştirmemeniz önemlidir.

Zaman içinde gerçek bir noktayı manipüle ediyorsanız, bu belirli bir günde belirli bir zamandır, o zaman bunu yapmanın tek yolu her zaman evrensel UTC zaman değerini kullanmaktır. Bunu asla saat dilimiyle ilgili bir değer olarak saklamaya çalışmayın. Bu zaman değerini bir kullanıcıya görüntülerken, daima o zaman kullanıcının saat dilimine dönüştürün. (Hem saati hem de tarihi saat dilimine bağlı olarak unutmayın.)

Diğer kavram ise "her Salı 20:00" gibi bir "zaman ifadesi" dir. İnsanların randevu almasına izin verdiğinizden özellikle bahsettiniz ve yinelenen randevularınız varsa, böyle bir ifadeye ihtiyacınız var. Herhangi bir standart ifade dili bilmiyorum, ama ne kullanırsanız kullanın, onu belirten kişinin zaman dilimine göre olacaktır. Bunu açıkça belirtmek en iyisidir, örneğin "Pasifik Saat Dilimi'nde her Salı 20:00". Bir zaman ifadesi durumunda, bunu her zaman bir dize olarak saklarsınız ve hiçbir zaman sistem saat formatlarını içermezsiniz.

Bunun daha fazla tartışmasını blogumda görün


1

Buradaki birçok yanıt UTC olarak depolamayı göstermektedir. Ama buna çok dikkat et. Örneğin, randevuyu 12: 00'da planlıyorsanız, ancak randevu yaz saati uygulamasındaki değişiklikten sonra gerçekleşirse ne olur? UTC, randevu kaydedildiğinde dst'nin etkin olup olmadığı hakkında hiçbir bilgi tutmaz. Bir çok büyük, ünlü sistem bu hatayı yaptı, burada bir kullanıcı yaz aylarında sabah 9'da bir e-posta gönderiyor ve daha sonra kışın gönderilen zaman sabah 8'de gösteriyor, çünkü UTC'den gelen hesaplama, tarih saatine baktığınız zamana bağlı, tarih saatinin ne zaman kaydedildiği değil.

Çok daha iyi, kullanıcının her zaman seçtiği zamanları olmasını istediğini varsaymaktır. UTC dönüşümü yok, zaman dönüşümü yok, saat dilimi bilgisi yok, hiçbir şey yok. 21 Mart 2016 günü 08: 00-12: 00 saatleri arasında randevu almak tam da bu. Yerel saat veya UTC saati kullanmayın, ancak belirtilmemiş saat (json'da bu z veya + yoktur, temelde .NET'te DateTime.Kind = DateTimeKind.Unspecified vardır).

Tabii ki, kullanım durumunuz farklı zaman dilimlerinden biriyle toplantılar yapan bir şirketseniz ve bu bilgileri örneğin bir şirket takviminde görmek, ancak kullanıcıların saat diliminde ne zaman olduğunu görmelerine izin vermek istiyorsanız, daha karmaşık hale gelir. Zamanın farklı zaman dilimlerindeki (tedarikçi ve müşteri) farklı insanlar için doğru olması gerekir.

Bu gibi durumlarda, kaydetmek istediğiniz bile olabilir zaman randevum nedir saat diliminde, veritabanına kaydedilmiş ve bu dahil dst olup olmadığını. Bu şekilde, yerel saati her zaman ya şimdi ne olacağı ya da tarihsel olarak olması amaçlanan başka bir şeye geri hesaplayabilirsiniz. Zaman dilimleri çok statik olmadığından işleri daha da karmaşık hale getirir.

Neyse ki, http://nodatime.org/ gibi kütüphaneler buraya gelir ve şiddetle tavsiye edilir. Tarihlerle çok daha tutarlı çalışırlar. O zaman bile, tüm datetime değişkenlerinizi ve mantığınızı kendi paketleyicilerinize sarmanızı, arayüzleri alay edebilmeleri için kullanmanızı öneririm ve daha sonra yine de mantığı değiştirebilirsiniz.


Sonuçlarınıza tamamen katılmıyorum, ancak gün ışığında tasarruf değişikliği planlanan öğlen toplantısı, geleceğe birkaç yıl rezerve edilen öğlen haftalık toplantısı gibi özel bir zorluktur.
Bent

" Tabii ki, kullanım durumunuz farklı zaman dilimlerinden biriyle toplantılar yapan bir şirketseniz ve bu bilgileri örneğin bir şirket takviminde görmek, ancak kullanıcıların saat diliminde saatin kaç olduğunu görmelerine izin vermek istiyorsanız, daha karmaşık hale geliyor. "- hemen hemen her şirket. Çin ve Hindistan dışındaki çok az şirket saat dilimleri arası randevuları görmezden gelebilir.
Ross Patterson

" Bu şekilde, yerel saati her zaman ya şimdi ne olacağı ya da tarihsel olarak olması amaçlanan şey için başka bir şeye geri hesaplayabilirsiniz. Çünkü zaman dilimleri çok statik değildir, işleri daha da karmaşık hale getirir. " - bir kez hesaplamalar yapacağınızı kabul edersiniz, gerçekten zaman için tek bir temsil seçmeniz gerekir. UTC, EST (EST5EDT değil), IST, her neyse. Ancak, aynı alanda birden fazla zaman dilimine dayanan değerlere sahip olamaz ve bunlar üzerinde meşru bir toplu işlem gerçekleştiremezsiniz. Görüntü işleme, tabii. Ama bu kolay kısmı.
Ross Patterson

En azından hala doğru bir şekilde UTC'ye dönüştürebilirsiniz. Retrospect'te bu bilgilerden istediğiniz zaman bir hesaplama tablosu veya değer oluşturabilirsiniz. Ama asla başka yoldan gidemezsin. SQL 2016'nın bunu yerel olarak desteklemeye başladığını unutmayın, ancak ne yazık ki hala - en azından tarihsel olarak - oldukça doğru kayıt defteri verilerine dayanmıyor - ama yine de başka bir gelişme.
Arwin
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.