Yalnızca C # 'da Tarih için bir tür - Neden Tarih türü yok?


108

C # projemizde bir tarihi zamansız temsil etme ihtiyacımız var. DateTime'ın varlığını biliyorum, ancak günün bir saatini de içeriyor. Belirli değişkenlerin ve yöntem argümanlarının tarihe dayalı olduğunu açıkça belirtmek istiyorum . Dolayısıyla DateTime.Datemülkü kullanamıyorum

Bu soruna standart yaklaşımlar nelerdir? Eminim bununla ilk karşılaşan ben değilim? DateC # 'da neden sınıf yok ?

Bir yapı ve belki de DateTime üzerinde bazı uzantı yöntemleri kullanan ve belki == ve <,> gibi bazı operatörleri uygulayan güzel bir uygulaması olan var mı?


1
Açık ve net anlambilim istemeyi anlasam da, hangi özel problemler DateTimeyaratır?
Jeff Sternal

15
1 Yöntemin başlangıcındaki saatleri çıkarmamı hatırlamam gerekiyor. 2 Yalnızca tarihlerde çalıştığını iyi iletmiyor. Bu, örneğin dar bir tipin yeterli olacağı Db'den depolama ve yükleme sırasında önemlidir. Programlama bilgisayarlar için değil insanlar için bir paylaşımdır
Carlo V. Dango

6
Sadece bir randevu sınıfının olmamasının büyük bir sorun olduğunu ve DateTime kullanmanın hiç de iyi olmadığını söylemek istedim. "Tarihlerinizi" tarih-saat olarak kaydeder kaydetmez, yerel ayar / saat dilimi gün ışığı tasarrufu sorunlarına rehin kalırsınız. Zaman bölümünü bir kenara atmak, tüm tarihlerinizi saatlerin değiştiği (!) Bir gün geri gönderebilir. Ve farklı saat dilimlerindeki kullanıcılar, tarih-saatleri dönüştürmeye çalıştıklarında farklı tarihler görecekler. Tarih-saatler, zamandaki kesin anları temsil etmek için iyidir (bir noktadan veya her neyse), ancak soyut bir tarihi temsil etmek için çok uygun değildir.
TheMathemagician

3
Daha sonra benzer bir soru stackoverflow.com/questions/7167710/… ve Jon Skeet bir Tarih olması gerektiğini söylüyor.
göz

9
Bir tamsayı veri türü bir ondalık sayıya göre yalnızca tarih veri türü DateTime'dır. Bir tarihe ihtiyacımız olmadığını savunanlar, sadece zaman bölümünü atabilirsiniz çünkü ondalık kısmı atabileceğimiz için tamsayılara ihtiyacımız olmadığını söylemeye benzer. Dünyamız, zaman içermeyen bir tarih kavramına sahiptir. 5 Mart 5 Mart 00:00:00 değil.
Belirsiz

Yanıtlar:


55

Bu klasik soruya bir güncelleme eklememe izin verin:

  • Jon Skeet'in Noda Time kitaplığı artık oldukça olgun ve yalnızca tarih içeren bir türe sahipLocalDate . (Bu durumda yerel, yalnızca biri için yerel anlamına gelir , kodun çalıştığı bilgisayarda yerel olması gerekmez.)

  • Yalnızca tarih adı verilen Datebir tür , corefxlab projesi aracılığıyla .NET Core'a önerilen bir eklemedir . BulacaksınSystem.Time pakette, bir TimeOfDaytür ve mevcut türlere yönelik çeşitli uzatma yöntemleriyle birlikte .

Bu sorunu önemli ölçüde inceledim, bu nedenle bu türlerin gerekliliğine ilişkin birkaç nedeni de paylaşacağım:

  1. Yalnızca tarih ile gece yarısı tarih değeri arasında mantıksal bir tutarsızlık vardır.

    • Her yerel gün değil vardır her zaman diliminde bir gece yarısı. Örnek: Brezilya'nın ilkbahar-ileriye doğru yaz saati uygulaması geçişi, saati 11:59:59'dan 01:00:00'a taşır.

    • Tarih-saat her zaman gün içindeki belirli bir zamanı ifade ederken yalnızca tarih, günün başlangıcını, günün sonunu veya günün tüm aralığını ifade edebilir.

  2. Tarihe saat eklemek tarihin değişmesine neden olabilir , zaman dilimleri çok dikkatli izlenmezse, değer bir ortamdan diğerine geçerken . Bu genellikle JavaScript'te ( Datenesnesi gerçekten bir tarih + saattir) oluşur, ancak .NET'te de veya JavaScript ile .NET arasında veri aktarılırken serileştirmede de kolayca gerçekleşebilir.

  3. Bir DateTimeXML veya JSON (ve diğerleri) ile seri hale getirmek , önemli olmasa bile her zaman zamanı içerecektir. Bu çok kafa karıştırıcı, özellikle doğum tarihleri ​​ve yıl dönümleri gibi zamanın alakasız olduğu şeyleri düşünürsek.

  4. Mimari DateTimeolarak bir DDD değer nesnesidir , ancak Tek Sorumluluk İlkesini çeşitli şekillerde ihlal eder :

    • Bir tarih + saat türü olarak tasarlanmıştır, ancak genellikle yalnızca tarih (saati yok sayarak) veya yalnızca günün saati (tarihi yok sayarak) olarak kullanılır. (TimeSpan aynı zamanda günün saati için de kullanılır, ancak bu başka bir konudur.)

    • DateTimeKindİliştirilmiş değer .Kindözelliği, üçe tek tip böler Unspecifiedtür gerçekten yapının orijinal niyet olduğunu ve yol o kullanılmalıdır. UtcTür hizalar özellikle UTC ile değer ve Localnazik şekilde uyum ortamın yerel saat dilimiyle değer.

      Tür için ayrı bir bayrağa sahip olmanın sorunu, her a tükettiğinizde DateTime, kontrol etmeniz gerekmesidir ..Kind almak ne davranış karar vermek. Çerçeve yöntemlerinin tümü bunu yapar, ancak diğerleri genellikle unutur. Türün artık değiştirmek için iki farklı nedeni (değer ve tür) olduğundan bu gerçekten bir SRP ihlalidir.

    • Bunların ikisi, derleyen, ancak genellikle anlamsız olan veya yan etkilerden kaynaklanan garip uç durumlara sahip API kullanımlarına yol açar. Düşünmek:

      // nonsensical, caused by mixing types
      DateTime dt = DateTime.Today - TimeSpan.FromHours(3);  // when on today??
      
      // strange edge cases, caused by impact of Kind
      var london = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
      var paris = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
      var dt = new DateTime(2016, 3, 27, 2, 0, 0);  // unspecified kind
      var delta = paris.GetUtcOffset(dt) - london.GetUtcOffset(dt);  // side effect!
      Console.WriteLine(delta.TotalHours); // 0, when should be 1 !!!

Bir süre Özetle, DateTime olabilir bir kullanılacak tarih okunur, sadece kullandığı zaman göz ardı etmek çok dikkatli olduğunu ve aynı zamanda UTC veya diğer gelen ve dönüştürmek için denemek için çok dikkatli olduğunu zaman her yerde böyle yapmalı Zaman dilimleri.


2
Keşke System.Time.Date.NET çerçevesinde bitecek olsaydı: /
Robert Jørgensgaard Engdahl

1
Bunu bugün kullanabilirsiniz, sadece corefx myget beslemesine abone olun ve System.Timediğer tüm paketler gibi çekebilirsiniz . Henüz "resmi" değil.
Matt Johnson-Pint

16

Size adanmış bir saf Datesınıf olmadığından şüpheleniyorum çünkü zaten bununla DateTimebaşa çıkabilecek bir sınıfınız var . Sahip olmakDate , tekrarlara ve kafa karışıklığına yol açar.

Standart yaklaşımı istiyorsanız, saat değeri 12:00:00:00 (00:00:00) olarak ayarlanmış a'nın DateTime.Dateyalnızca tarih kısmını veren mülke bakın DateTime.


61
Özel bir Date sınıfının büyük bir avantajı, saat dilimlerinin ve yaz saati uygulamasının karmaşıklığından etkilenmemesidir.
Dimitri C.

3
@DimitriC. Katılmıyorum - DateTime'ı UTC ile kullanabilirsiniz ve açıklanan sorunların yanı sıra DateTime ile de sıkıntı yaşamazsınız, sadece tarihler isteseniz bile zamanı içeren matematik işlemleri yapabilirsiniz (yani 20 x 2saat çıkarırsam bana tarihi verin bugünden itibaren).
Robert MacLean

10
UTC'yi ve saat dilimiyle ilgili herhangi bir şeyi düşünmek zorunda olmak, yalnızca bir enerji israfıdır, çünkü ayrı bir Tarih sınıfı ile kolayca önlenebilir. Ve Date ve DateTime arasında herhangi bir karışıklık görmüyorum.
maulik13

6
C # 'ın gerçekten bir Date sınıfına sahip olması gerektiğini kabul edin. Saat dilimi dönüştürme olayı sadece denizaltı hatalarının sürekli bir kaynağı değil, aynı zamanda zamana dayalı değil, bir iş gününe dayanan şeylerle uğraşırken sadece acı vericidir.
Julian Birch

1
@RobertMacLean: "Bugünden 20 x 2 saat çıkarırsam tarihi" dikkate almanın bir anlamı yok. Bu örnekte, bugünü "bugün gece yarısı" olarak kabul ediyor musunuz? "bugün öğlen vakti"? vb. Bu problem iyi formüle edilmemiştir. "Bugün gece yarısı" demek istiyorsanız, zaten DateTime ile çalışıyorsunuz, DateTime ile çalışıyorsunuz. Saatleri çıkarmak için bir güne değil bir saate ihtiyacınız var.
xavier

12

Refsrcfeedback@microsoft.com adresine e-posta gönderdim ve bu onların cevabı

Marcos, burası böyle sorular sormak için iyi bir yer değil. Http: //stackoverflow.com'u deneyin Kısa cevap, zamandaki bir noktayı temsil edecek bir modele ihtiyacınız olduğudur ve DateTime bunu yapar, bu pratikte en yararlı senaryodur . İnsanların zamandaki noktaları işaretlemek için iki kavramı (tarih ve saat) kullanması keyfi bir şeydir ve ayırmak kullanışlı değildir.

Sadece garanti edildiği yerde ayırın, işleri körü körüne yapmak uğruna yapmayın. Şöyle düşünün: DateTime'ı Tarih ve Saate bölerek çözülen probleminiz nedir? Ve şimdi sahip olmadığın hangi sorunları yaşayacaksın? İpucu: .NET çerçevesindeki DateTime kullanımlarına bakarsanız: http://referencesource.microsoft.com/#mscorlib/system/datetime.cs#df6b1eba7461813b#references Çoğunun bir yöntemden döndürüldüğünü göreceksiniz. DateTime gibi tek bir konseptimiz olmasaydı, bir çift Tarih ve Saat döndürmek için parametreler veya Tuples kullanmanız gerekirdi.

HTH, Kirill Osenkov

E-postamda, DateTime'ın makinenin saatini almak için TimeZoneInfo kullanması nedeniyle olup olmadığını sorguladım - Now mülkiyetinde. Bu yüzden "iş kuralları" "çok bağlı" olduğu için, bunu bana itiraf ettiler.


Bu gönderi, yerleşik bir tarih sınıfına sahip olmama tasarım kararının arkasındaki düşünceler hakkında gerçekten fikir veriyor. Onlara gönderdiğiniz soru neydi? @ TheMathemagician yukarıda listelenen nedenlerden dolayı bu karara katıldığımı ima etmek istemiyorum.
Robert Jørgensgaard Engdahl

@ RobertJørgensgaardEngdahl ne yazık ki artık o e-posta hesabına erişimim yok. Ama onlara DateTime yapısında Time ve Date'i neden bir araya getirdiklerini sordum. Ve TheMathemagician ile aynı fikirde olduğumu düşündüm, sanırım MS bu tasarım yaklaşımını benimsedi çünkü uluslararası bir şirket olarak ihtiyaçlarını karşılıyor - ve şimdi değiştirmek için geç - ancak kavramları bölmek değil.
MVCDS

2
Belki MS, tüm çabayı göstererek bir SpaceTimesınıf uygulayabilir ! Hey, Einstein'a göre, uzay ve zaman birbirine sıkı sıkıya bağlı, bu yüzden ikisini de ayırt etmemiz gerekmiyor, değil mi? Basitçe, nerede (!!!!!!!!!!!) C # için çok yeni değilim, ama söylemek zorundayım, bu VB.NET gelen bir mayın tarlası date, Today(), nowvb No DateTimehiçbir çöp önek dalga geçiyor. (Ve bu noktalı virgüller ve bu büyük / küçük harf duyarlılığı kesinlikle rahatsız edici! Sadece beni şimdi vurun!)
SteveCinq

2
Ve kendi SQL Server'larının Datetürü ve sonucu tür olmalıdır Date- eğer bu Datetür bir sonuç ise zaman olmadan dizge olarak bekleniyordu. Örneğin, Delphi ayrıca DateTime olarak Date'e sahiptir, ancak typeinfo, Date ve DateTime için farklıdır.
user2091150

1
Kirill Osenkov, "Neden Tarih ve Saat Sınıflarına karşı Tarih Saat Sınıflarına göre ayrı Tarih ve Saat Sınıfları yok ?" Sorusuna yanıt veriyor . Gerçek Q "Neden değildi da ayrı Tarih ve Zaman Sınıfları var mı?". Tarih-saat kavramının birçok kullanım durumu için Tarih ve Saatin tek bir Sınıfta birleştirilmesi gerektiğini anlıyorum . Bununla birlikte, yalnızca bir tarih kavramının geçerli kullanım durumları kadar, belki de daha fazlası kadar çok olabilir . Ve elbette bir zaman kavramının birçok geçerli kullanım durumu da vardır.
Tom


4

Tarih karşılaştırmaları yapmanız gerekiyorsa şunu kullanın:

yourdatetime.Date;

Ekranda görüntülüyorsanız kullanın

yourdatetime.ToShortDateString();

.Date kısmı aradığım şeydi.
Brendan Vogt

3

Tahmin etmeme izin verin: Belki de bunun nedeni SQL Server 2008'e kadar SQL'de Tarih veri türü olmaması, dolayısıyla SQL sunucusunda saklamanın zor olması olabilir mi? Ve sonuçta bir Microsoft Ürünü mü?


Bir db tarih saati, C # tarih saatinden farklıdır. Bir db tarih saatinin bir saat dilimi yoktur, bu nedenle gerçekte belirli bir anı ifade etmezler. Ancak C # anın olduğunu bilir ve UTC döneminden bu yana tik işaretlerini saklar.
artsrc

2
tartışma özel TARİH ile ilgili, tarih saat kısmı hakkında çok fazla değil, bu yüzden yapmaya çalıştığınız noktayı anlamıyorum.
Pleun

Bu soruya bir cevap vermiyor. Bir yazarı eleştirmek veya açıklama istemek için yazının altına bir yorum bırakın.
Barranka

@Barranka - Soru "C # 'ta neden Date sınıfı yok?"
STLDev

2

Neden böyle olduğunu kim bilebilir? .NET çerçevesinde birçok kötü tasarım kararı vardır. Ancak bence bu oldukça önemsiz. Zaman bölümünü her zaman göz ardı edebilirsiniz, bu nedenle bazı kodlar bir DateTime'ın yalnızca tarihten daha fazlasına atıfta bulunmasına karar verse bile, önemseyen kod yalnızca tarih kısmına bakmalıdır. Alternatif olarak, yalnızca bir tarihi temsil eden yeni bir tür oluşturabilir ve ağır işi (hesaplamalar) yapmak için DateTime'daki işlevleri kullanabilirsiniz.


1
Sadece bir tarih kullanmak isteyip istemeseniz de bunun kötü bir karar olduğunu düşünmüyorum. Size olumsuz oy vermeyeceğim ama bu benim fikrim.
JonH

İyi ifade ettiğimi sanmıyorum. Aslında onunla pek bir problemim yok, ancak iki veya üç türe sahip olmanın bir soyutlama / zarafet açısından nasıl daha uygun olacağını görebiliyordum. Demek istediğim, .NET çerçevesinde gerçekten kafanızı kaşıyabilecek pek çok şey olduğu ve bu konuda çok üzülmeye değmeyeceğiydi, özellikle de bu "sorunun" bazı korkunç tasarım kararlarına kıyasla (genel kısıtlamalar).
siride

+1 çünkü doğru ... .NET'in tek sorunu (veya en büyüğü) bu muydu :-) :-) SQL Server'ın DATE ve TIME türlerini eklemek için kaç sürümüne ihtiyaçları vardı? Ve orada ÇOK daha yararlıydılar (en azından bütünlük nedeniyle)
xanatos

Ayrıca şunu da eklemeliyim ki, "her şey -100 noktadan başlar" ın çok kötü bir çerçeve oluşturmanın iyi bir yolu olduğunu ve bu çöplükte kalan şeylerden biri de bu olabilir.
siride

2
Kodun 1 bölümü .Date özelliğini kullanmayı ihmal ettiğinden ve bu nedenle düzgün bir şekilde karşılaştırılamadığı için bu sorunla ısırıldım. Kesinlikle Bu tür hataları önlemek için, her zaman saklamaz bir tarihi tipi için ihtiyaç olduğunu düşünüyorum
JoelFan

2

Neden? Sadece spekülasyon yapabiliriz ve mühendislik problemlerini çözmeye yardımcı olmak için fazla bir şey yapmaz. İyi bir tahmin şu kiDateTime böyle bir yapının sahip olabileceği tüm işlevselliği içermesidir.

Sizin için gerçekten DateTimeönemliyse, yalnızca tarihi gösteren kendi değişmez yapınızı sarın (veya DateTime.Datemülke bakın).


2

Robert'ın cevabına ek olarak DateTime.ToShortDateStringyönteme de sahipsiniz . Ayrıca, gerçekten bir Date nesnesi istiyorsanız, her zaman Adapter modelini kullanabilir ve DateTime nesnesini yalnızca istediğinizi (yani ay, gün, yıl) gösterecek şekilde sarabilirsiniz.


2

Her zaman için DateTime.Datezaman bölümünü kesen özellik vardır DateTime. Belki de DateTime'ı kendi Tarih türünüzde özetleyebilir veya sarmalayabilirsiniz.

Ve neden sorusu için, sanırım Anders Heljsberg'e sormanız gerekecek.


1

Çünkü tarihi bilmek için, saati de içeren sistem saatini (kene cinsinden) bilmeniz gerekir - öyleyse bu bilgiyi neden atasınız?

DateTimeDatezamanın hiç umrunda değilse bir mülkü vardır .


1

Evet, System.DateTime da mühürlendi. Daha önceki yayınlarda belirtildiği gibi zamanın dize değerini elde etmek için özel bir sınıf oluşturarak bazılarının bununla oyun oynadığını gördüm, örneğin:

class CustomDate
{
    public DateTime Date { get; set; }
    public bool IsTimeOnly { get; private set; }

    public CustomDate(bool isTimeOnly)
    {
        this.IsTimeOnly = isTimeOnly;
    }

    public string GetValue()
    {
        if (IsTimeOnly)
        {
            return Date.ToShortTimeString();
        }

        else
        {
            return Date.ToString();
        }
    }
}

GetShortTimeString'i yeni bir sınıf olmadan düz eski bir DateTime türünden kolayca çıkarabileceğiniz için bu belki gereksiz olabilir.


0

DateTime nesnesinden yalnızca tarih bölümünü almak için Tarih veya Bugün özelliklerini kullanırsanız.

DateTime today = DateTime.Today;
DateTime yesterday = DateTime.Now.AddDays(-1).Date;

Ardından, tarih bileşenini yalnızca saat bileşeni gece yarısına ayarlı olarak alacaksınız.


1
bu kesinlikle istediğim şey değil
Carlo V. Dango

@Carlo V. Dango: Katılmıyorum. Sanırım tam da istediğin buydu.
siride

1
@Carlo V. Dango: Bu özelliklerin başarmanıza izin vermemesi için özellikle ne yapmayı düşünüyorsunuz?
eph_tagh

5
Oldukça kolaydır: Bir Tarih belleği ayak izi muhtemelen bir DateTime'ın bellek ayak izinin yalnızca yarısı kadardır (64 bit yerine 32). Aptal iş arkadaşınızın tarihinize değiştirmediğinden emin olabilirsiniz. Eğer (bir hata için) DateTime DateTimeKind.Local olarak ayarlanmışsa ve saat UTC olarak normalize edilmişse, Tarih büyük olasılıkla değişecektir (XmlSerialization kullanılarak başıma geldi ve JSON'a kötü bir şekilde gidildi) ... Yeterli mi?
xanatos
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.