Neden tarihleri ​​veritabanından bir dize olarak döndürmüyorsunuz?


41

Tipik bir web uygulamasında, tarihler güçlü bir şekilde yazılan veritabanı katmanından alınır (örneğin, System.String'in tersine bir System.DateTime olarak c #).

Bir tarihin dize olarak ifade edilmesi gerektiğinde (örneğin, bir sayfada görüntülenir), DateTime'dan dizgeye dönüşüm sunum katmanında yapılır.

Bu neden? DateTime'ı veritabanı katmanındaki bir dizeye dönüştürmek neden kötü bir şey?

Ayrıca sohbetteki hararetli tartışmaya ve bunların hepsini başlatan asıl soruya bakınız .


73
Size şunu sorayım: o zaman her bir teli bir dizgeye çevirir miydiniz? Date'i farklı kılan nedir?
gardenhead


8
Diğer adamın yanlış olduğu ve herkesin haklı olduğu çok açık görünüyor. Burada gerçekten bir soru değil
gardenhead

7
Bazen veritabanının dışında tarih matematik yapmanız gerekir. Tüm sahip olduğunuz teller ise oldukça zor.
Eric King

14
Başka bir sorun - ne tür bir ipucuna ihtiyacınız var? Bir tarih tarihini bir dize olarak temsil etmenin bir sürü yolu vardır. Sadece o anki zamanın döndüğü, dönemden bu yana saniyeler içinde temsil edilen, bir dizge olarak (örneğin, şu anki saat "1474496980") olan bir veritabanım olsaydı. Bu yararlı olur mu? Böyle bir veritabanı kullanmak ister misiniz?
riwalk,

Yanıtlar:


168

Tarihler, DateTimes ve gerçekten başka bir yazılmış nesne, genellikle başka bir tipte yapılmasını istediğiniz ana kadar - özellikle bu tip insan tarafından okunabilen bir form olduğunda ve özellikle de kayıp olduğunda / tek yönlü dönüşüm türü.

Neden? Bu türün size uygun eşitlik testi, toplama ve çıkarma, karşılaştırma (en az, daha büyük), zaman dilimi ve yerel ayar işlevselliği (özellikle zamanla ilgili her şey için önemli) gibi kullanışlı bir çok işlevsellik sağladığı varsayıldığından, vb. Amerikalıları ve "Ay Günü [th], Yılı" biçimini ve aynı zamanda "Gün Ay Yılı" nın ortak İngiliz stilini veya "Yıl-Ay-Gün" ün ISO standardını desteklemek istediğinize karar verirseniz? Bir dize olsaydı ve bu değişikliği yapmanız ve bir Tarihte yeniden ayrıştırmanız gerekiyorsa ne yapardınız? Uh, hayır, teşekkürler - pek çok kötülük var ve en iyisi, tamamen kaçınılması gereken korkak bir şekilde.

Daha spesifik olarak, sunum katmanını verilerden ayrı tutan katmanlı mimariden söz ettiniz. Bu aslında bir Tarihi Tarih olarak değil dize olarak iletmenin diğer büyük nedenidir - çünkü tarih ne tür bir dize biçimlendirmesi yapılmalıdır? İngilizce, Çince, saniye veya milisaniye olmadan, tam ay adı veya rakamlarla, tarih alanını daha sonra sıralamak ister misiniz (bir dize sıralaması doğru çalışması için belirli bir dize formatı gerektirir), vb. Tüm bunlar bir sunum meselesi - kullanıcının verileri nasıl görüntülemesi gerektiği - ve bu mantığı başka bir yere koymak, ilk aşamada katmanlı mimariye sahip olmanın avantajını sınırlayacaktır. Veritabanının gelecekteki tarihi nasıl görmek istediğinizi bilmesi veya umursaması gerekmemelidir.

Son olarak, zamanı önemseyen neredeyse tüm karmaşık uygulamalar (bu, katmanlı mimarilerin ne olduğu) kaçınılmaz olarak zamanları / tarihleri ​​çok, çok farklı şekillerde ve çoğu zaman da mimarlığın farklı seviyelerinde kullanacaktır. Zaman ve tarihlerle ilgili yazılan nesneler gerçekten iyi bir sebepten dolayı var: zamanın kendisi ve özellikle insan takvimi sistemleri çok garip ve zor. Sonuçta, zamanlar ve tarihler, tamsayıların ve kayan noktaların dizge olmadığı aynı nedenden ötürü karakter dizileri değildir ve sadece karakter dizileriymiş gibi davranmaya çalışırsanız hayatınızı zorlaştırır, çünkü sadece karakter dizileri değiller.


26
Sadece 1 kelimesini aptalca kullandığın için. Sizin zorlayıcı argümanlarınız ve kapsamlı açıklamalarınızla aynı fikirdeyim, ancak bu yüzden oturum açıp size oy vermek zorunda kaldım.
Adrian Larson,

1
Tarihin belirli bir zamanından bu yana tarihin saniye olarak belirtilmesi, farklı takvimler arasında da güçlüdür. Mesela İslami ve Çin takvimleri Greogriyan aylarını, yıl sayılarını vs. kullanmaz.
rexkogitans 22:16

Tarihler genellikle "X gün önce" olarak sunulur. Bunu orijinal değerine geri döndürmede iyi şanslar.
Ajan_L

5
DST değişikliği (ve diğer benzeri) sorunları da unutmayalım. Will "6 Kasım 2016 01:30:26" Bu tarih ve saat olmuş olacağı ilk defa veya ikinci defa olmak? UTC DateTime en azından benzersizdir ve o zaman için yerel temsile her zaman çevirebilirsiniz - diğer tarafa geri dönmek her zaman mümkün değildir.
J ...

3
Why? Because it is assumed that the type provides you with lots of handy built in functionalityBence bu sadece ikincil. Asıl sebep, türün size bir şeyin ne olduğunu söylemesidir . Bir tarih bir dize değildir , sadece kolayca okunabilir bir dize çevrilir.
Doval

53

Veri zamanını bir dizgeye dönüştürmek için web sunucusunu kullandığını söylüyor. Diyorum ki bunu web sunucusunda değil veritabanı sunucusunda yapın. Neden daha iyi olduğunu düşünüyorsun? - MT Başkanı

Tipini bilmek istiyorum.

Veritabanınızın bilgileri bir dizgede, bazı ints veya byte'larda tutması umrumda değil, çünkü sonunda zaten her zaman byte'lar. Veritabanında gerekenden daha fazla yer kaplayan o dize beni rahatsız etmiyor. Beni rahatsız eden şey şu tarihe karışıyor:

2016/11/10

Ve onbirinci ay mı, yoksa onuncu ay mı bilmiyorum.

Ama söylediğin doğrulandı. Doğrulama işlemlerinden geçirdiğinizden emin olun. Tarih tamamen doğru. Ama burada bu şeyi sürdürüyorum ve tek bildiğim tarihin bir dize olduğu. Sana bunun hangi tarihte olduğunu bile söyleyemem.

"Kasım ayının onuncu günü, efendimizin iki on altıncı yılında."

Bu bir ip. Sunularımızdan birinin de bu formatta olması gerekiyor. Veritabanının tüm tarihleri ​​dizelere dönüştürdüğünü söylediniz, değil mi? Bununla eğlenin.

Veritabanının görevi, veri bulunmayan verileri saklamaktır. Elbette, bunu dizelerde yapabilirsin ama sonra diğer biçimlerde sunumu faydalı kılmak için onu çözümlemelisin. DB'nin sunduğu herhangi bir tür için standart ayrıştırılmış biçimde saklamak, sunu yapma kararı vermeden olabileceğimiz en yakın hazır olmamızı sağlar. DB'nin bu tür bir dize veya ints veya byte ile desteklemesi gerçekten benim için önemli değil. Ne yaptığını bildiği sürece.

Ancak, DB'ye bir tarihle uğraştığımızı ve bir tarihi bir dize olarak kaydettiğimizi bilmediğiniz zaman, bir sunumu diğerlerine göre daha önce sunmakta ve tercih ediyor olursunuz. Bu, diğer tüm sunucuları dönüştürmeden önce ayrıştırmaya zorlar. Hayır, veritabanı sunum katmanının bir parçası değil. Olmasını istemeyin.

Aynı şekilde sunum katmanı veritabanının bir parçası değildir, bu nedenle bir raporun veritabanı ayrıntılarını birleştirmesi akıllıca olmaz. Türlere etki etmek çok daha sağlam.


Bu cevap, depolamayı dizeler olarak ele alır . Bununla birlikte, tarihlerin yerel bir tarih türünde depolanmasının genel biçimini ele almaz, ancak bunu CONVERT (T-SQL) gibi işlevleri kullanarak SQL sorgusunda bir dize olarak biçimlendirmek veya bir DBMS'nin genellikle tarihlerini seri hale getirmesidir. Sorgu ne olursa olsun, yapılandırılabilir bir formatta bir dizgeye dönüşür. Örneğin: postgresql.org/docs/9.5/static/…
saat

Bu bir rapor. Depolamadan sonra olur. Doğum tarihimi yaşıma dönüştürmek gibi.
candied_orange 22.06

2
Ben sadece OP'nin konusu "tarih nasıl olduğu gibi, cevabınızı uzatmak için teşvik istedi alınan veritabanı katmanından". Bir raporun biçimlendirilmiş ve yerelleştirilmiş tarih dizeleri için veritabanını sorguladığı, tartışmalı bir şekilde itiraz edilmiş olsa da, bir kalıp vardır. OP'nin bu kullanımdan argümanlarını duymak istediğini düşünüyorum. Yapacağımı biliyorum.
saat

@dcorking notu güncellemesi.
candied_orange

+1 değirmene daha fazla su ekleyerek: sadece mutlak anın en önemli olduğu birden fazla zaman dilimini kapsayan ve kurulu bir taban üzerinde bir sistem oluşturun ve her yerde <-> dizgisi dönüşümleriyle ne kadar iyi çalıştığınızı görün. En kötüsü, insanların kendi eklentilerini yaratmaları için bir uzatma noktası oluşturun ve dizgilerin bu zaman damgalarının ne kadar tutarlı olacağını görmesi için zaman damgası verin!
Newtopian

19

yerel

Sunum amacıyla dizgiye dönüşüm tarihi, kullanıcı tercihlerini bilmeyi gerektirir, çünkü aynı tarih genellikle farklı yerlerdeki kullanıcılar için farklı gösterilmelidir. Uygulamanızda tek yerel kullansanız bile, doğru davranış yerel ayarını kullanmalısınız uygulaması yerine veritabanı sunucusunun; ve şu anda tesadüfen uysalar bile aynı olmaları garanti edilmez.

Evrensel bir tarih veri türünden yerel ayara özgü bir dizgeye dönüşüm, sunum katmanında gerçekleşmelidir çünkü bu dönüştürmenin nasıl gerçekleştirileceğini bilen katmandır .


3
Yerel bir uyumsuzluğun gerçek hayattan bir örneği için Maine, ABD kullanıcıları için bir uygulama yazdığınızı hayal edin ve ardından Amazon'un batı sahil sunucusu çiftliğinde barındırılır. ;) Aslında bu pek olası bir durum değil.
jpmc26

@ jpmc26 Farkı anlamadım - Maine ABD'nin geri kalanı için farklı bir tarih formatı kullanıyor mu?
Pete Kirkham

2
@ PeteKirkham Maine ve ABD'nin batı kıyısı, 3 saat arayla ayrılan zaman dilimlerini kullanır.
jpmc26

1
Ya da başka bir gerçek hayat senaryosunda: İsviçre'de dört (Almanca, Fransızca, İtalyanca, İngilizce) farklı dilde, farklı yerel ayarlarda (ve biraz farklı biçimlendirme kuralları olan) müşterilere hizmet vermek zorunda olan bir sunucu çalıştırdığınızı düşünün . Böyle bir durumda sunucunuz için doğru yerel ayarı seçmede iyi şanslar.
Voo

1
@ jpmc26 saat dilimleri ve yerel ayarları aynı şey değildir. Örneğin, Glasgow İskoçya, Atlanta ABD ve Pune Hindistan'da ofislerimiz var. Bu ofislerdeki danışmanlar sırayla dünyanın her yerindeki siteleri (kampüsler, hastaneler, oteller vb.) İzlerler. Uygulama veritabanı UTC'de çalışır ancak izlenen sitenin yerel saatindeki zamanlarını görüntüler. ABD danışmanları tarihlerini MM / DD / YYYY olarak belirledi, ancak İngiltere ve Hindistan yerel ayarları DD / MM / YYYY - bu, sitenin veya kullanıcının saat dilimine değil yerel ayarlara bağlı.
Pete Kirkham

9

Aynı nedenden ötürü , uygulama katmanına vurduğu anda sadece herhangi bir türü bir dizgiye kör olarak dönüştürmek istemeyeceğiniz aynı nedenle istenmeyen bir durumdur . Kullanıcıya sunmadan önce bu nesneyi bir şekilde kullanmak isteyeceğiniz yüksek bir ihtimaldir (eğer kullanıcıya sunsanız bile). Bu özel örnek için, nesnede tarih tarihi matematiği yapmanız gerektiğini hayal edin. Görüntülemeden önce nesneyi tam olarak bir dizgeye dönüştürmenin bir dezavantajı yoktur.


4

Türler bir sebepten dolayı varlar, eğer fayda sağlamazlarsa, o zaman onlara sahip olamazdık ve kullanmayacağız ve sadece "tip" olacaktı ve her şey böyle olacaktı. Sadece uygun değil aynı zamanda güvenlik ve verimlilik de sağlarlar. Aşağıda, türleri her zaman yerel biçiminde , dize olarak değil de sürdürmeniz gerektiğinin bir listesi verilmiştir . DateTimeÇoğu zaman örnek olarak kullandım ancak aynı ilkeler tamsayılar, ondalık sayılar, ikili vb. Gibi ilkel türler için de geçerli.


Bilgi deposu

Kısıtlamalar

Türü Kısıtlaması

Neredeyse tüm veri depoları veri üzerindeki kısıtlamaları belirlemeye izin verir, buna tip kısıtlamaları da dahildir. Bir DateTimeörnek belirtmenin temel yararlarından biri , depolanan verilerin bu türle sınırlı olacağıdır. Verinin depoya nasıl yerleştirildiğine bakılmaksızın, bir tarih saatinden başka bir şey girmek asla mümkün olmayacaktır. Sonuncusu, doğrudan mağaza ile etkileşime giren çoklu işlemlerin olduğu daha büyük sistemler için önemlidir. Ayrıca, Şubat ayının 30 yıl gibi hatalı tarihlerini eklemeyi de içerir (herhangi bir yılın), Şubat ayının sadece artık yılda 29 gün, artık olmayan yıllarda 28 gün olabilir.

Doğrulama Kısıtlamaları

Girilen bir tarihin geçerli tarihi geçmemesini veya bir başlangıç ​​tarihinin bitiş tarihinden önce gerçekleşmesini sağlamak gibi Veri Deposunda uygulanabilecek doğrulama kısıtlamaları da vardır.

Operasyonlar

Çoğu veri deposunda ayrıca MS Sql Server gibi DateAddveya DatePartiçerisinde yerleşik işlemler / işlevler vardır . Bu, veriler hala depodayken (uygulamaya henüz alınmamış) filtreleme veya belirli verileri seçmenize olanak sağlar.

Evrensel Kabul Edilen Format

Yerel tip kullanılarak, aynı zamanda mağaza ile de etkileşime giren diğer geliştiricilerin veya sistemlerin, bu ilkel tipin nasıl depolandığına dair dakika ayrıntıları konusunda bilgilendirilmeleri gerekmez. Bu tip bir dizge olarak kaydedildiyse durum bu değildir, o zaman herkesin o DateTimedizge gösteriminin biçimini anladığından emin olmalısınız . Bu sistem, veri kaynağındaki yerleri, bölgeleri ve kültürleri, uygulamanın fiziksel konumunu ve bu verilerle etkileşime giren son kullanıcının / sistemin özniteliklerini kapsayan verilerle uğraşırken kırılgan hale gelir. Örnek: Bir ülkedeki tarih formatı MM / gg / yyyy (ABD'de olduğu gibi) olabilir, ancak bir diğerinde gd / MM / yyyy olabilir, bu farkın neredeyse imkansız hale geldiğini tespit etmek mümkündür.

hız

Alma hızı, doğrulama hızı, işlemlerin hızı ve depolama verimliliği de aynı zamanda önemli faktörlerdir. Alma hızına örnek: veri depoları sütunlarda indekslere izin verir ve bu indeksler, tür kendi formatında saklanırsa genellikle daha verimli kullanılabilir.

Uygulama

Veri erişimi

Sorguların mağazaya karşı yürütülmesi, yerel tip sistemi geliştiriciler olarak kullanarak daha basit hale gelir, bir kez daha depolama formatı hakkında tahmin yapmak zorunda kalmazsınız. Hemen hemen tüm veri deposu uygulama sağlayıcıları ( örnek: ado.net ), içeri aktarılan yerel türlere göre uygun parametreli sorgu oluşturmak için mekanizmalar sağlar. Aynı dizeleri ile yapmak çok hantal ve kırılgan / hata eğilimli olacaktır.

command.Parameters.Add(new SqlParameter("@startDate", SqlDbType.Date) {Value = myDateInstance.Date});

Operasyonlar

Koddaki yerel türler ayrıca .net türü gibi standart işlemler sağlar System.Date. İşlemler genellikle tarih ekleme, tarihler arasındaki farkı bulma vb. Gibi nitelikte matematikseldir. Yine de, bu dize türlerinde kolayca yapılması mümkün değildir.

Sunum katmanı

yerel

İlkel bir tür nihayet sunum katmanındaki bir dizgeye dönüştürüldüğünde ( bunu yapmak için program yığındaki doğru yer ) programcı şimdi sunulduğu içeriğe göre doğru göstermesi için çeşitli seçeneklere sahiptir. Bu bağlam genellikle verilerin gerçek anlamını ve kullanıcının yerel ayarını içerir.

örnek 1

Bir datetime örneği, kullanıcının yerel ayarına göre otomatik olarak biçimlendirilebilir.

DateTime.Now.ToString("D", CultureInfo.GetCultureInfo(userContext.Culture))
Örnek 2

Ondalık bir örnek bir miktarı (para birimini) temsil ediyor olabilir ve kullanıcının yerel ayarı daha sonra miktarı tercihlerine göre görüntülemelidir. Bir c # uygulaması kullanarak değeri görüntüleyebilir

amount.ToString("C", CultureInfo.GetCultureInfo(userContext.Culture))

Farklı kültürler sayıları farklı gösterdiği için bu kritik olabilir. ABD döneminde (.) Ve virgül (,), Hollanda'da olduğu gibi tam tersi anlama sahiptir.

yer

Bu, DateTimeörneklere çok özeldir . Bir tarih ve saat, belirli bir zamanda meydana gelen bir oluşumu temsil eder, ancak bu genellikle kendi zaman dilimine bağlı olarak kullanıcıya iletilmeli / sunulmalıdır. Örnek: ABD'deki Doğu Timezone'daki bir kullanıcı için bir DateTimeörnek 2016-09-21T23:38:21.399Zgörüntülenebilir 9/21/2016 5:21 PM. Bunu başarmanın birçok yolu vardır, ancak tarih saatinin bir dize türü olarak bellekte veya bir dize türü olarak veri deposunda tutulması imkansız hale gelir.


Genel kural

Herhangi bir ilkel türün bir dize temsiline dönüştürülmesi söz konusu olduğunda, bir uygulamanın genel 2 kuralları şöyledir:

  • Girdi kabul edilirken, bu girdiyi program yığında olabildiğince erken doğru ilkel türe dönüştürün (genellikle sunum katmanında)
  • Görüntülenecek verileri alırken, bu verileri program yığınında olabildiğince geç dize olarak gösterime dönüştürün (yine, genellikle sunum katmanında)

0

Randevunuz için belirsiz bir format kullandığınız sürece, bunu yaparken hiçbir şey yapmazsınız (hizmetlerde her zaman yapılır). Açıkça söylemek gerekirse, demek istediğim sadece tarihi belli değil (örn. AA / GG / GG / AA / GG) ve aynı zamanda hangi saat diliminde olduğu da açıktır. . UTC tabanlı zaman dizgilerini şiddetle tercih ederim.

Artıları:

  • Standartlara dayalı tarih / saat Dizeleri taşınabilir ve anlaşılması kolaydır
  • Genellikle DB'lerdeki tarihler bir zaman bileşeni içerir. Bu, verileriniz için anlamlı değilse, aslında işleri basitleştirebilir.

Eksileri:

  • Veri boyutu Bir DB içindeki bir tarihin dahili formatı genellikle o tarihin String göstergesinden çok daha az yer kullanır.
  • Genel olarak müşteride gerçek bir tarih veya saat yapısına girmek isteyeceksinizdir, böylece ayrıştırmada fazladan zaman olabilir.

Birisi bunu yapmak istediklerini söyleseydi, “neden?” Diye sorardım. çünkü bunun için çok fazla bir nokta yok. Birinin bir Dize olarak tarihi döndürmek istemesinin sebebi, sadece doğrudan gösterecekleriyse, bu, Dizeleri DB'den kullanmak için iyi bir neden değildir.

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.