System.DateTime stellt ein Datum und eine Uhrzeit dar, vom Jahr 1 bis zum Jahr 9999, mit einer Genauigkeit von 100 Nanosekunden (ein „Tick“). System.TimeSpan stellt eine Dauer dar: die Differenz zwischen zwei DateTime-Werten. Beide sind unveränderliche Werttypen (Structs), jede Operation gibt also einen neuen Wert zurück.
Ausgabe:
2026-09-24 00:00:00
2026-09-24 14:30:00
14:30:05.250
2026 9 24
14:30
Thursday
267
2026-09-24 00:00
14:30:00
Jedes Beispiel auf dieser Seite gibt Datumswerte mit einem expliziten Formatstring aus. Das Standard-ToString() folgt der aktuellen Kultur (9/24/2026 2:30:00 PM in den USA, 24.09.2026 14:30:00 in Deutschland), seine Ausgabe hängt also vom Rechner ab. Die Formatcodes findest du unter DateTime-Format.
Ein ungültiges Datum wirft: new DateTime(2026, 2, 30) löst eine ArgumentOutOfRangeException aus, ebenso Monat 13 oder Stunde 24.
Now, UtcNow und Today
Drei statische Properties lesen die Uhr:
Beispielausgabe:
Now: 2026-09-24 18:20:41 (Local)
UtcNow: 2026-09-24 16:20:41 (Utc)
Today: 2026-09-24 00:00:00
In diesem Beispiel liegt die lokale Zeitzone zwei Stunden vor UTC, die ersten beiden Zeilen unterscheiden sich also um zwei Stunden; auf einem auf UTC eingestellten Rechner stimmen sie überein. Die Property Kind hält fest, ob ein Wert Local, Utc oder Unspecified ist (der Standard für selbst erzeugte Datumswerte). Nimm DateTime.UtcNow für alles, was du speicherst, protokollierst, vergleichst oder an ein anderes System schickst: Es springt nicht, wenn die Sommerzeit beginnt oder endet, und bedeutet auf jedem Server denselben Zeitpunkt. Wandle nur in lokale Zeit um, wenn du einem Menschen einen Wert anzeigst.
Um zu messen, wie lange Code braucht, nimm System.Diagnostics.Stopwatch statt zwei DateTime.Now-Werte zu subtrahieren; er hat eine viel feinere Auflösung und ist von Uhrkorrekturen nicht betroffen.
Zeit addieren und subtrahieren
AddDays, AddHours, AddMinutes, AddSeconds, AddMonths und AddYears geben einen neuen DateTime zurück. Übergib eine negative Zahl, um zurückzugehen. Weil DateTime unveränderlich ist, muss das Ergebnis zugewiesen werden:
Ausgabe:
2026-01-31
2026-02-03 09:00
2026-01-30 21:00
2026-02-28
2027-01-31
10:30
29
True
AddMonths begrenzt auf den letzten Tag des Monats, wenn der Tag nicht existiert: 31. Januar plus ein Monat ist der 28. Februar (oder 29. in einem Schaltjahr), nicht der 3. März. Zweimal einen Monat zu addieren und einmal zwei Monate zu addieren kann daher verschiedene Datumswerte ergeben.
Datumswerte subtrahieren: TimeSpan
Wird ein DateTime von einem anderen subtrahiert, ergibt sich ein TimeSpan:
Ausgabe:
3.20:30:00
Days: 3, Hours: 20, Minutes: 30
TotalDays: 3.85
TotalHours: 92.5
TotalMinutes: 5550
Nights: 4
Das ist der Teil der API, den Leute am häufigsten falsch verwenden. Days, Hours, Minutes und Seconds sind die Komponenten der Spanne (3 Tage, 20 Stunden, 30 Minuten). TotalDays, TotalHours und TotalMinutes sind die gesamte Dauer in einer Einheit, als double. „Wie viele Stunden ist der Gast geblieben?“ ist TotalHours (92.5), nicht Hours (20).
Die letzte Zeile zeigt einen verwandten Punkt: 3.85 Tage sind vergangen, aber der Gast ist 4 Nächte geblieben. Der Vergleich der .Date-Anteile zählt Kalendertage, und das ist meist, was Abrechnungen und Anzeigen wie „noch n Tage“ brauchen.
TimeSpan-Werte erzeugen und formatieren
Ausgabe:
02:15:00
01:30:00
1.12:00:00
True
03:45:00
True
02:15
36h 0m
00:00:00
TimeSpan unterstützt +, -, Vergleiche, Duration() (Absolutwert) und Negate(). Benutzerdefinierte Formate wie @"hh\:mm" brauchen einen Backslash vor wörtlichen Zeichen, und hh zeigt dort nur die Stundenkomponente (0 bis 23). Für Dauern über einen Tag baue den Text daher aus TotalHours, wie in der vorletzten Zeile.
Datumswerte vergleichen
DateTime unterstützt ==, !=, <, >, <= und >= sowie CompareTo und DateTime.Compare. Um nur das Datum zu vergleichen und die Uhrzeit zu ignorieren, vergleiche die .Date-Properties:
Ausgabe:
True
True
1
True
2026-09-01
Für „liegt dieser Zeitstempel am 30. September?“ vergleiche wie oben mit < gegen den Beginn des nächsten Tages. check <= end würde alles nach Mitternacht am letzten Tag ausschließen, weil end 2026-09-30 00:00:00 ist.
Vergleiche schauen nur auf die Ticks, nicht auf Kind: Ein Local-Wert und ein Utc-Wert, die gleich ausgegeben werden, gelten als gleich, obwohl sie verschiedene Zeitpunkte sind. Ein weiterer Grund, gespeicherte Zeiten in UTC zu halten.
Wochentag und Wochenbeginn
DayOfWeek ist ein Enum von Sunday (0) bis Saturday (6). Mit Arithmetik darauf findest du Wochentage und Wochengrenzen:
Ausgabe:
Thursday
4
Weekend: False
Week starts 2026-09-21 (Monday)
Next Friday: 2026-09-25
2026-09-01 to 2026-09-30
Die Tagesnamen, die DayOfWeek.ToString() ausgibt, sind immer englisch. Für einen lokalisierten Namen formatiere das Datum mit "dddd" und einer Kultur.
Datumswerte aus Strings parsen
Wenn du das Format der Eingabe kennst, nimm ParseExact oder TryParseExact mit CultureInfo.InvariantCulture. Der Formatstring verwendet dieselben Codes wie beim Formatieren:
Ausgabe:
2026-09-24 00:00
2026-09-24 18:05
'2026-02-28' -> Saturday, February 28
'2026-02-30' -> invalid
'28.02.2026' -> invalid
'' -> invalid
2026-02-28
2026-09-24 10:00 Utc
DateTime.Parse(text) ohne Format versucht, mit der aktuellen Kultur zu raten. "03/04/2026" ist auf einem US-Rechner der 4. März und auf einem britischen der 3. April, und ein Datum, das auf deinem Laptop geparst wird, kann auf einem Server eine FormatException werfen. Behalte Parse für Eingaben, die ein lokaler Benutzer tippt; nimm ParseExact mit der invarianten Kultur für Dateien, APIs und Datenbanken. ParseExact wirft FormatException, wenn der Text nicht passt; TryParseExact gibt stattdessen false zurück.
Ein Alter berechnen
Geburtsdaten zu subtrahieren und durch 365 zu teilen ist rund um Geburtstage und Schaltjahre falsch. Vergleiche die Jahre und korrigiere, wenn der diesjährige Geburtstag noch nicht war:
Ausgabe:
36
35
18
70 days to go
DateTimeOffset
Ein DateTime hält über das vage Flag Kind hinaus nicht fest, in welcher Zeitzone er liegt. DateTimeOffset speichert den Wert zusammen mit seinem Versatz zu UTC und identifiziert so immer einen exakten Zeitpunkt:
Ausgabe:
2026-09-24 14:00 +02:00
2026-09-24 12:00
2026-09-24 12:30
00:30:00
21:00 +09:00
Nimm DateTimeOffset (oder DateTime-Werte in UTC) für Zeitstempel: wann eine Bestellung aufgegeben, wann eine Nachricht gesendet wurde. Datenbanken und JSON-Serializer kommen gut damit zurecht. Für die Umrechnung zwischen benannten Zeitzonen mit Sommerzeitregeln nimm TimeZoneInfo.ConvertTime; die Zonen-IDs unterscheiden sich in älteren .NET-Versionen je nach Betriebssystem ("Europe/Paris" unter Linux, "Romance Standard Time" unter Windows), und ab .NET 6 werden beide akzeptiert.
DateOnly und TimeOnly (ab .NET 6)
Viele Werte sind ein Datum ohne Uhrzeit (ein Geburtstag, ein Fälligkeitsdatum) oder eine Uhrzeit ohne Datum (Öffnungszeiten). .NET 6 hat dafür zwei Typen hinzugefügt:
// .NET 6 and later
DateOnly birthday = new DateOnly(1990, 9, 24);
DateOnly due = DateOnly.FromDateTime(DateTime.Today).AddDays(14);
int daysLeft = due.DayNumber - DateOnly.FromDateTime(DateTime.Today).DayNumber;
TimeOnly opens = new TimeOnly(9, 0);
TimeOnly closes = new TimeOnly(17, 30);
bool isOpen = TimeOnly.FromDateTime(DateTime.Now).IsBetween(opens, closes);
Sie beseitigen eine Klasse von Bugs, bei denen eine versehentliche Uhrzeit oder Zeitzone ein Datum um einen Tag verschiebt. Älterer Code und Code für .NET Framework oder Unity verwendet DateTime mit der Uhrzeit auf Mitternacht.
Häufige Fehler
- Das Ergebnis von
AddDaysverwerfen.DateTimeist unveränderlich; weise den zurückgegebenen Wert zu. HoursstattTotalHoursverwenden. Komponenten gegenüber Gesamtdauer.DateTime.Nowspeichern. Speichere UTC und wandle für die Anzeige um.ToString()ohne Format aufrufen in Logs, Dateien oder Tests, wo die Ausgabe von der Kultur des Rechners abhängt.- Maschinendaten mit
DateTime.Parseparsen. NimmParseExactund die invariante Kultur. mmundMMverwechseln in Formatstrings (Minuten und Monate). Siehe DateTime-Format.
Häufig gestellte Fragen
Was ist der Unterschied zwischen DateTime.Now und DateTime.UtcNow?
DateTime.Now ist die aktuelle Zeit in der lokalen Zeitzone des Rechners, mit Kind auf Local. DateTime.UtcNow ist die aktuelle Zeit in UTC, mit Kind auf Utc, und es ist außerdem schneller, weil die Zeitzonenumrechnung entfällt. Speichere und vergleiche Zeitstempel in UTC und wandle nur für die Anzeige in lokale Zeit um.
Wie berechne ich in C# die Differenz zwischen zwei Datumswerten?
Subtrahiere sie: TimeSpan gap = end - start;. Lies dann gap.TotalDays, gap.TotalHours oder gap.TotalMinutes für die gesamte Dauer als double, oder gap.Days für den Anteil ganzer Tage. Für Kalendermonate oder Jahre gibt es keine eingebaute Property, weil Monate unterschiedlich lang sind; vergleiche die Felder für Jahr und Monat selbst.
Was ist der Unterschied zwischen TimeSpan.Hours und TotalHours?
Hours ist nur die Stundenkomponente, von 0 bis 23, nachdem ganze Tage abgezogen sind. TotalHours ist die gesamte Dauer in Stunden, als double. Bei einer Spanne von 1 Tag und 3 Stunden ist Hours 3 und TotalHours 27. Hours dort zu verwenden, wo TotalHours gemeint war, ist ein sehr häufiger Bug.
Wie parse ich in C# einen Datumsstring?
Wenn du das Format kennst, nimm DateTime.ParseExact(text, "yyyy-MM-dd", CultureInfo.InvariantCulture) oder DateTime.TryParseExact, um bei fehlerhafter Eingabe false statt einer FormatException zu bekommen. DateTime.Parse errät das Format aus der aktuellen Kultur, daher bedeutet 03/04/2026 in den USA den 4. März und in Großbritannien den 3. April.
Warum ändert AddDays meinen DateTime nicht?
DateTime ist ein unveränderlicher Werttyp. AddDays, AddHours und die anderen Methoden geben einen neuen DateTime zurück und lassen das Original unverändert, du musst das Ergebnis also zuweisen: due = due.AddDays(7);.
Wann sollte ich DateTimeOffset statt DateTime verwenden?
Nimm DateTimeOffset für Zeitstempel, die einen exakten Zeitpunkt identifizieren müssen, etwa wann eine Bestellung aufgegeben oder ein Logeintrag geschrieben wurde, besonders wenn Daten zwischen Servern und Zeitzonen wandern. Er speichert den Versatz zu UTC mit dem Wert. DateTime genügt für reine UTC-Zeitstempel und für Datumswerte ohne sinnvolle Zeitzone.