Ein Typ für Datum nur in C # - warum gibt es keinen Datumstyp?

106

In unserem C # -Projekt müssen wir ein Datum ohne Uhrzeit darstellen. Ich weiß von der Existenz der DateTime, sie enthält jedoch auch eine Tageszeit. Ich möchte deutlich machen, dass bestimmte Variablen und Methodenargumente datumsbasiert sind . Daher kann ich die DateTime.DateEigenschaft nicht verwenden

Was sind die Standardansätze für dieses Problem? Sicher bin ich nicht der erste, der darauf stößt? Warum gibt es Datein C # keine Klasse?

Hat jemand eine nette Implementierung mit einer Struktur und vielleicht einigen Erweiterungsmethoden in DateTime und vielleicht einige Operatoren wie == und <,>?

Carlo V. Dango
quelle
1
Ich verstehe zwar, dass ich eine explizite, klare Semantik haben möchte, aber welche spezifischen Probleme entstehen DateTime?
Jeff Sternal
15
1 Ich muss daran denken, die Stunden zu Beginn der Methode zu entfernen. 2 es kommuniziert nicht gut, dass es nur an Daten funktioniert. Dies ist wichtig, z. B. beim Speichern und Laden von Db, wo ein schmaler Typ ausreicht. Programmierung ist Gemeinschaft für Menschen, nicht Computer
Carlo V. Dango
4
Ich wollte nur sagen, dass das Fehlen einer Datumsklasse eine große Sache ist und die Verwendung von DateTime überhaupt nicht gut ist. Sobald Sie Ihre "Daten" als Datums- und Uhrzeitangaben speichern, sind Sie Geisel von Sommerzeitproblemen in der Region / Zeitzone. Wenn Sie den Zeitteil wegwerfen, können Sie alle Ihre Daten an einem Tag zurückschicken, an dem sich die Uhren ändern (!). Und Benutzer in verschiedenen Zeitzonen sehen unterschiedliche Daten, wenn sie versuchen, die Datums- und Uhrzeitangaben zu konvertieren. Datums- und Uhrzeitangaben eignen sich gut für die Darstellung präziser Zeitpunkte (im Handumdrehen oder was auch immer), sind jedoch für die Darstellung eines abstrakten Datums sehr ungeeignet.
TheMathemagician
2
Eine spätere ähnliche Frage stackoverflow.com/questions/7167710/… , und Jon Skeet sagt, es sollte ein Datum geben.
Goodeye
6
Ein Datentyp nur für Datum ist DateTime, während ein ganzzahliger Datentyp eine Dezimalzahl ist. Diejenigen, die argumentieren, wir brauchen kein Datum, weil Sie den Zeitteil einfach wegwerfen können, sagen, wir brauchen keine ganzen Zahlen, da wir den Dezimalteil wegwerfen können. Unsere Welt hat das Konzept eines Datums, das keine Zeit enthält. Der 5. März ist nicht der 5. März 00:00:00.
Vage

Antworten:

54

Gestatten Sie mir, dieser klassischen Frage ein Update hinzuzufügen:

  • Die Noda Time- Bibliothek von Jon Skeet ist jetzt ziemlich ausgereift und hat einen Nur-Datum-Typ namens LocalDate. (Lokal bedeutet in diesem Fall nur lokal für jemanden , nicht unbedingt lokal für den Computer, auf dem der Code ausgeführt wird.)

  • Ein Nur-Datum-Typ namens Dateist eine vorgeschlagene Ergänzung zum .NET Core über das corefxlab- Projekt. Sie finden es im System.TimePaket zusammen mit einem TimeOfDayTyp und mehreren Erweiterungsmethoden für die vorhandenen Typen.

Ich habe dieses Problem eingehend untersucht, daher werde ich auch einige Gründe für die Notwendigkeit dieser Typen nennen:

  1. Es gibt eine logische Diskrepanz zwischen einem Nur-Datum- und einem Mitternachtsdatum-Wert.

    • Nicht jeder lokale Tag hat in jeder Zeitzone Mitternacht. Beispiel: Brasiliens Sommerzeitübergang im Frühjahr bewegt die Uhr von 11:59:59 auf 01:00:00 Uhr.

    • Eine Datums- und Uhrzeitangabe bezieht sich immer auf eine bestimmte Uhrzeit innerhalb eines Tages, während sich eine Datums- und Uhrzeitangabe auf den Tagesanfang, das Tagesende oder den gesamten Tagesbereich beziehen kann .

  2. Das Anhängen einer Uhrzeit an ein Datum kann dazu führen, dass sich das Datum ändert, wenn der Wert von einer Umgebung in eine andere übergeben wird, wenn die Zeitzonen nicht sehr genau überwacht werden. Dies tritt häufig in JavaScript auf (dessen DateObjekt tatsächlich ein Datum + eine Uhrzeit ist), kann jedoch auch in .NET oder bei der Serialisierung leicht auftreten, wenn Daten zwischen JavaScript und .NET übertragen werden.

  3. Das Serialisieren von a DateTimemit XML oder JSON (und anderen) enthält immer die Zeit, auch wenn dies nicht wichtig ist. Dies ist sehr verwirrend, insbesondere wenn man Dinge wie Geburtsdaten und Jahrestage berücksichtigt, bei denen die Zeit keine Rolle spielt.

  4. Architektonisch DateTimehandelt es sich um ein DDD- Wertobjekt , das jedoch in mehrfacher Hinsicht gegen das Prinzip der Einzelverantwortung verstößt :

    • Es ist als Datums- und Uhrzeittyp konzipiert, wird jedoch häufig nur als Datum (ohne Berücksichtigung der Uhrzeit) oder nur als Uhrzeit (ohne Berücksichtigung des Datums) verwendet. ( TimeSpanwird auch oft für die Tageszeit verwendet, aber das ist ein anderes Thema.)

    • Der DateTimeKindan die .KindEigenschaft angehängte Wert teilt den einzelnen Typ in drei Teile. Die UnspecifiedArt ist wirklich die ursprüngliche Absicht der Struktur und sollte auf diese Weise verwendet werden. Die UtcArt richtet den Wert speziell auf UTC aus und dieLocal Art richtet den Wert an der lokalen Zeitzone der Umgebung aus.

      Das Problem mit einem separaten Flag für Art ist, dass Sie jedes Mal, wenn Sie ein konsumieren DateTime, überprüfen müssen , welches Verhalten Sie anwenden sollen.Kind . Die Framework-Methoden tun dies alle, aber andere vergessen es oft. Dies ist wirklich eine SRP-Verletzung, da der Typ jetzt zwei verschiedene Gründe hat, sich zu ändern (den Wert und die Art).

    • Die beiden führen zu API-Verwendungen, die kompiliert werden, aber oft unsinnig sind oder seltsame Randfälle aufweisen, die durch Nebenwirkungen verursacht werden. Erwägen:

      // 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 !!!

Zusammenfassend DateTime lässt sich sagen, dass a zwar nur für ein Datum verwendet werden kann , dies jedoch nur dann der Fall sein sollte, wenn an jedem Ort, an dem es verwendet wird, die Zeit sehr sorgfältig ignoriert wird und auch sehr darauf geachtet wird, nicht zu versuchen, von und nach UTC oder einem anderen Wert zu konvertieren Zeitzonen.

Matt Johnson-Pint
quelle
2
Wenn nur System.Time.Dateim .NET Framework
landen
1
Sie können dies heute verwenden, einfach den corefx myget-Feed abonnieren und System.Timewie jedes andere Paket einbinden . Es ist nur noch nicht "offiziell".
Matt Johnson-Pint
17

Ich vermute, es gibt keine dedizierte reine DateKlasse, weil Sie bereits eine haben, DateTimedie damit umgehen kann. Dies Datewürde zu Doppelarbeit und Verwirrung führen.

Wenn Sie den Standardansatz wünschen, schauen Sie sich die DateTime.DateEigenschaft an, die nur den Datumsteil von a DateTimemit dem auf 12:00:00 Mitternacht (00:00:00) festgelegten Zeitwert angibt.

Robert MacLean
quelle
59
Ein großer Vorteil einer dedizierten Datumsklasse besteht darin, dass sie nicht unter der Komplexität von Zeitzonen und Sommerzeit leidet.
Dimitri C.
3
@ DimitriC. Ich bin anderer Meinung - Sie können DateTime mit UTC verwenden und leiden nicht unter den erläuterten Problemen. Außerdem können Sie mit einer DateTime auch dann, wenn Sie nur Daten möchten, noch Zeitrechnungen durchführen (dh geben Sie mir das Datum an, wenn ich 20 x 2 Stunden subtrahiere von heute).
Robert MacLean
@ Robert MacLean: Vielen Dank, dass Sie die Benutzerfreundlichkeit von UTC DateTimes hervorgehoben haben. Ich habe einige Tests durchgeführt und es scheint, als ob DateTimeKind. Nicht spezifizierte Verhaltensweisen wie UTC in Bezug auf Subtraktionen. Wenn Sie also vorsichtig mit der "Art" von DateTimes sind, mit denen Sie arbeiten, wird alles gut.
Dimitri C.
10
Über UTC und alles, was mit Zeitzone zu tun hat, nachdenken zu müssen, ist nur eine Energieverschwendung, da es durch eine separate Datumsklasse leicht vermieden werden kann. Und ich sehe keine Verwechslung zwischen Date und DateTime.
maulik13
5
Stimmen Sie zu, dass C # wirklich eine Date-Klasse haben sollte. Die Zeitzonenumwandlung ist nicht nur eine ständige Quelle von U-Boot-Fehlern, sondern es ist auch einfach schmerzhaft, wenn es um Dinge geht, die eher auf einem Geschäftstag als auf einer Zeit basieren.
Julian Birch
12

Ich habe eine E-Mail an [email protected] gesendet und das ist ihre Antwort

Marcos, dies ist kein guter Ort, um solche Fragen zu stellen. Versuchen Sie es mit http://stackoverflow.com. Die kurze Antwort lautet, dass Sie ein Modell benötigen, um einen Zeitpunkt darzustellen, und DateTime tut dies. Dies ist das nützlichste Szenario in der Praxis . Die Tatsache, dass Menschen zwei Konzepte (Datum und Uhrzeit) verwenden, um Zeitpunkte zu markieren, ist willkürlich und nicht nützlich, um sie zu trennen.

Entkoppeln Sie nur dort, wo dies gerechtfertigt ist. Tun Sie Dinge nicht nur, um Dinge blind zu machen. Stellen Sie sich das so vor: Welches Problem haben Sie, das durch Aufteilen von DateTime in Datum und Uhrzeit gelöst wird? Und welche Probleme werden Sie bekommen, die Sie jetzt nicht haben? Hinweis: Wenn Sie sich die Verwendung von DateTime im gesamten .NET-Framework ansehen: http://referencesource.microsoft.com/#mscorlib/system/datetime.cs#df6b1eba7461813b#references Sie werden dass die meisten von einer Methode zurückgegeben werden. Wenn wir kein einziges Konzept wie DateTime hätten, müssten Sie Parameter oder Tupel verwenden, um ein Paar aus Datum und Uhrzeit zurückzugeben.

HTH, Kirill Osenkov

In meiner E-Mail hatte ich gefragt, ob DateTime TimeZoneInfo verwendet, um die Uhrzeit der Maschine abzurufen - in Now-Anstand. Ich würde also sagen, es liegt daran, dass "die Geschäftsregeln" "zu gekoppelt" sind, das haben sie mir bestätigt.

MVCDS
quelle
Dieser Beitrag gibt wirklich Einblicke in die Gedanken hinter der Entwurfsentscheidung, keine eingebaute Datumsklasse zu haben. Was war die Frage, die Sie ihnen geschickt haben? Ich möchte nicht implizieren, dass ich dieser Entscheidung aus genau den Gründen zustimme, die @TheMathemagician oben aufgeführt hat.
Robert Jørgensgaard Engdahl
@ RobertJørgensgaardEngdahl Leider habe ich keinen Zugriff mehr auf dieses E-Mail-Konto. Aber ich glaube, ich habe sie gefragt, warum sie Zeit und Datum in der DateTime-Struktur miteinander verbunden haben. Und obwohl ich TheMathemagician zustimme, denke ich, dass MS diesen Designansatz gewählt hat, weil er als internationales Unternehmen seine Bedürfnisse auszahlt - und jetzt zu spät ist, um ihn zu ändern -, während die Aufteilung der Konzepte dies nicht tut.
MVCDS
2
Vielleicht könnte MS einfach das ganze Schwein gehen und eine SpaceTimeKlasse implementieren ! Hey, laut Einstein sind Raum und Zeit eng miteinander verbunden, also sollten wir auch nicht zwischen ihnen unterscheiden müssen, oder? (!!!!!!!!!!!) Ich bin ein bisschen neu in C #, aber ich muss sagen, es ist ein Minenfeld von VB.NET kommen , wo ist, einfach, date, Today(), nowetc. Kein DateTimeMüll prefixing, nein herumalbern. (Und diese Semikolons und diese Groß- und Kleinschreibung sind sicher lästig! Erschießen Sie mich jetzt!)
SteveCinq
2
Und ihr eigener SQL Server- DateTyp und das Ergebnis müssen vom Typ sein Date- wenn es sich um ein DateTypergebnis handelt, das als Zeichenfolge ohne Zeit erwartet wird. Zum Beispiel hat Delphi auch Datum als DateTime, aber typeinfo unterscheidet sich für Date und DateTime.
user2091150
1
Kirill Osenkov beantwortet die Frage "Warum nicht getrennte Datums- und Zeitklassen gegenüber der DateTime-Klasse?". Das eigentliche Q war "Warum nicht auch separate Datums- und Zeitklassen haben?". Ich verstehe, dass Datum und Uhrzeit für die vielen Anwendungsfälle des Datums-Zeit- Konzepts in einer Klasse zusammengefasst werden sollten . Es gibt jedoch wahrscheinlich mindestens genauso viele, wenn nicht sogar mehr als gültige Anwendungsfälle nur eines Datumskonzepts . Und natürlich gibt es viele gültige Anwendungsfälle einer Zeit Konzept auch.
Tom
4

Wenn Sie Datumsvergleiche durchführen müssen, verwenden Sie

yourdatetime.Date;

Wenn Sie auf dem Bildschirm anzeigen, verwenden Sie

yourdatetime.ToShortDateString();
MattP
quelle
Der .Date-Teil ist das, wonach ich gesucht habe.
Brendan Vogt
3

Lassen Sie mich spekulieren: Vielleicht liegt es daran, dass es bis SQL Server 2008 keinen Datentyp "Datum" in SQL gab, sodass es schwierig wäre, ihn in SQL Server zu speichern? Und es ist doch ein Microsoft-Produkt?

Beschleunigen
quelle
Eine Datenbank-Datumszeit unterscheidet sich von einer C # -Datenzeit. Eine Datenbank datetime hat keine Zeitzone, sodass sie sich nicht auf einen bestimmten Zeitpunkt beziehen. Aber C # weiß, dass der Moment ist und speichert die Zecken seit der UTC-Epoche.
Artsrc
2
In der Diskussion geht es um das dedizierte DATUM, nicht so sehr um den Datums- / Uhrzeitteil, also verstehe ich den Punkt, den Sie ansprechen möchten, nicht?
Pleun
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klarstellung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag.
Barranka
@Barranka - Die Frage enthält "Warum gibt es in C # keine Datumsklasse?"
STLDev
2

Wer weiß, warum es so ist. Im .NET Framework gibt es viele schlechte Entwurfsentscheidungen. Ich denke jedoch, dass dies ein ziemlich kleiner ist. Sie können den Zeitteil jederzeit ignorieren. Selbst wenn sich ein Code dafür entscheidet, dass sich eine DateTime auf mehr als nur das Datum bezieht, sollte der betreffende Code immer nur den Datumsteil anzeigen. Alternativ können Sie einen neuen Typ erstellen, der nur ein Datum darstellt, und Funktionen in DateTime verwenden, um das schwere Heben (Berechnungen) durchzuführen.

Siride
quelle
1
Ich glaube wirklich nicht, dass dies eine schlechte Entscheidung war, ob Sie nur ein Datum verwenden möchten oder nicht. Ich werde dich nicht ablehnen, aber das ist meine Meinung.
JonH
Ich glaube nicht, dass ich es gut formuliert habe. Ich habe an sich eigentlich kein großes Problem damit, obwohl ich sehen konnte, wie zwei oder drei Typen unter dem Gesichtspunkt der Abstraktion / Eleganz angemessener wären. Mein Punkt war wirklich, dass es eine Menge Dinge im .NET Framework gibt, die dazu führen können, dass Sie sich am Kopf kratzen, und es lohnt sich nicht, sich darüber aufzuregen, insbesondere angesichts der Tatsache, dass dieses "Problem" im Vergleich zu einigen ungeheuerlichen Designentscheidungen (generisch) ziemlich geringfügig ist Einschränkungen).
Siride
+1, weil es stimmt ... war dies das einzige Problem (oder das größte) von .NET :-) :-) Wie viele Versionen von SQL Server brauchten sie, um einen DATE- und einen TIME-Typ hinzuzufügen? Und da waren sie VIEL nützlicher (zumindest aus Integritätsgründen)
Xanatos
Ich sollte auch hinzufügen, dass ich denke, dass "alles bei -100 Punkten beginnt" ein guter Weg ist, um ein pissarmes Framework zu erstellen, und dies könnte eines der Dinge sein, die in diesem Müll gefangen wurden.
Siride
2
Ich bin gerade von diesem Problem gebissen worden, weil 1 Teil des Codes die Verwendung der .Date-Eigenschaft vernachlässigt hat und daher nicht richtig verglichen wurde. Ich denke definitiv, dass ein
Datumstyp
2

Warum? Wir können nur spekulieren und es hilft nicht viel bei der Lösung technischer Probleme. Eine gute Vermutung ist, dass sie DateTimealle Funktionen enthält, die eine solche Struktur haben würde.

Wenn es Ihnen wirklich wichtig ist, schließen Sie einfach DateTimeIhre eigene unveränderliche Struktur ein, die nur das Datum verfügbar macht (oder sehen Sie sich die DateTime.DateEigenschaft an).

Jason
quelle
2

Neben Roberts Antwort haben Sie auch die DateTime.ToShortDateStringMethode. Wenn Sie wirklich ein Date-Objekt möchten, können Sie jederzeit das Adaptermuster verwenden und das DateTime-Objekt umbrechen, um nur das anzuzeigen, was Sie möchten (z. B. Monat, Tag, Jahr).

Matt
quelle
2

Es gibt immer die DateTime.DateEigenschaft, die den Zeitteil der abschneidet DateTime. Möglicherweise können Sie DateTime in Ihren eigenen Datumstyp kapseln oder einschließen.

Und für die Frage, warum, denke ich, müssen Sie Anders Heljsberg fragen.

Mikael Östberg
quelle
1

Denn um das Datum zu kennen, müssen Sie die Systemzeit (in Ticks) kennen, einschließlich der Uhrzeit - warum also diese Informationen wegwerfen?

DateTimehat eine DateEigenschaft, wenn Sie sich überhaupt nicht um die Zeit kümmern.

Massiv
quelle
1

Ja, auch System.DateTime ist versiegelt. Ich habe einige Leute gesehen, die damit Spiele gespielt haben, indem sie eine benutzerdefinierte Klasse erstellt haben, um den String-Wert der Zeit zu erhalten, wie in früheren Beiträgen erwähnt, wie zum Beispiel:

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();
        }
    }
}

Dies ist möglicherweise nicht erforderlich, da Sie GetShortTimeString einfach aus einem einfachen alten DateTime-Typ ohne eine neue Klasse extrahieren können

Ta01
quelle
0

Wenn Sie die Eigenschaften Datum oder Heute verwenden, um nur den Datumsteil vom DateTime-Objekt abzurufen.

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

Dann erhalten Sie die Datumskomponente nur, wenn die Zeitkomponente auf Mitternacht eingestellt ist.

eph_tagh
quelle
1
Dies ist definitiv nicht das, was ich wollte
Carlo V. Dango
@ Carlo V. Dango: Ich bin anderer Meinung. Ich denke, es ist genau das, was du wolltest.
Siride
1
@Carlo V. Dango: Was möchten Sie konkret tun, was Sie mit diesen Eigenschaften nicht erreichen können?
eph_tagh
5
Es ist ganz einfach: Ein Date-Speicherbedarf würde wahrscheinlich nur die Hälfte des Speicherbedarfs einer DateTime betragen (32 statt 64 Bit). Sie wären sicher, dass Ihr dummer Kollege nicht .AddHours (1) zu Ihrem Datum geändert hat, sondern "das Gleiche beibehalten" aus dem POV von "nur Datum". Wenn (für einen Fehler) die DateTime auf DateTimeKind.Local gesetzt ist und die Zeit auf UTC normalisiert ist, wird sich das Datum wahrscheinlich ändern (ist mir durch die Verwendung von XmlSerialization und einem schlecht gemachten Roundtrip zu JSON passiert) ... Ist es genug?
Xanatos