1. Formatierung von Daten
Wenn du denkst, dass die Ausgabe 2025-06-19T17:30:00 ziemlich cool aussieht, dann zeig dieses Format mal deiner Oma oder einem Buchhalter. Wahrscheinlich bevorzugen sie etwas Einfacheres: 19.06.2025 17:30. Deine englischsprachigen Kollegen erwarten 06/19/2025 5:30 PM. DevOps und Maschinen stehen sowieso auf 2025-06-19T17:30:00Z. Also kann ein DateTime im Speicher zig verschiedene Formate auf dem Bildschirm haben.
Das Gegenteil ist auch ein Klassiker: Der User gibt ein Datum ins Eingabefeld ein ("19.06.2025"), und wir müssen es in ein C#-Objekt umwandeln und dürfen nicht durcheinanderkommen, was Tag und was Monat ist. Automatisierung, Integrationen, Reports – überall ist die richtige Interpretation von Textdaten wichtig.
Basis-Formatierung
In C# kannst du ein Datums-/Zeitobjekt (DateTime, DateOnly, TimeOnly, DateTimeOffset) mit der Methode .ToString() in einen String umwandeln:
DateTime now = DateTime.Now;
Console.WriteLine(now.ToString()); // Ausgabe: 19.06.2025 17:30:25
Wenn du .ToString() ohne Parameter aufrufst, wird das Format der aktuellen Systemkultur verwendet (zum Beispiel zeigt ein deutsches Windows ein anderes Format als ein amerikanisches).
Standard-Formatstrings
Du kannst das Ausgabeformat explizit angeben, indem du sogenannte Standard-Formatstrings für Datum und Zeit verwendest:
| Format | Beschreibung | Beispielausgabe |
|---|---|---|
|
Kurzes Datum | 19.06.2025 |
|
Vollständiges Datum | 19. Juni 2025 |
|
Vollständiges Datum + kurze Zeit | 19. Juni 2025 17:30 |
|
Vollständiges Datum + vollständige Zeit | 19. Juni 2025 17:30:25 |
|
Kurzes Datum und Zeit | 19.06.2025 17:30 |
|
Kurzes Datum + vollständige Zeit | 19.06.2025 17:30:25 |
|
Kurze Zeit | 17:30 |
|
Vollständige Zeit | 17:30:25 |
|
Monat und Tag | 19. Juni |
|
Jahr und Monat | Juni 2025 |
|
ISO 8601 (Round-Trip) | 2025-06-19T17:30:25.0000000 |
Console.WriteLine(now.ToString("d")); // 19.06.2025
Console.WriteLine(now.ToString("F")); // 19. Juni 2025 17:30:25
Console.WriteLine(now.ToString("O")); // 2025-06-19T17:30:25.0000000
Custom (benutzerdefinierte) Muster
Wenn du speziellere Formate brauchst, kannst du eigene Muster verwenden:
| Symbol | Bedeutung |
|---|---|
| yyyy | Jahr, 4 Ziffern |
| yy | Jahr, 2 Ziffern |
| MM | Monat, 2 Ziffern |
| MMMM | Monatsname |
| dd | Tag, 2 Ziffern |
| d | Tag, 1-2 Ziffern |
| HH | Stunde (24h) |
| mm | Minuten |
| ss | Sekunden |
| tt | AM/PM |
Console.WriteLine(now.ToString("yyyy-MM-dd HH:mm")); // 2025-06-19 17:30
Console.WriteLine(now.ToString("dd.MM.yyyy")); // 19.06.2025
Console.WriteLine(now.ToString("dddd, MMMM d")); // Mittwoch, Juni 19
Kulturelle Unterschiede beim Formatieren
Wenn du das Ergebnis im Stil eines anderen Landes oder einer anderen Sprache haben willst, nutze die Überladung ToString(string, IFormatProvider):
var enUS = new System.Globalization.CultureInfo("en-US");
Console.WriteLine(now.ToString("D", enUS)); // June 19, 2025
- Wenn du ein festes Muster wie "MM/dd/yyyy" angibst, bekommst du unabhängig von der Kultur immer "06/19/2025".
- Aber wenn du nur "d" oder "D" verwendest, hängt das Format von der Kultur ab!
Wichtige Punkte bei der Formatierung
Beim Arbeiten mit Datumsformaten ist es wichtig, den Unterschied zwischen Standard- und Custom-Formaten zu verstehen. Standardformate (wie "d", "F", "G") passen sich automatisch an die Systemkultur an, was für User-Interfaces praktisch ist, aber beim Datenaustausch zwischen Systemen zu Problemen führen kann. Custom-Formate geben dir volle Kontrolle über die Ausgabe, brauchen aber mehr Feintuning.
Besonders wichtig ist das Format "O" (oder "o") – das ist das sogenannte "Round-Trip"-Format, das garantiert, dass ein Datum, das in einen String und zurück umgewandelt wird, exakt gleich bleibt. Dieses Format ist besonders wichtig beim Serialisieren von Daten oder beim Übertragen übers Netzwerk.
2. Parsen von Daten und Uhrzeiten: Wie man aus einem String ein Objekt bekommt
Einfachstes Parsen: DateTime.Parse
DateTime.Parse ist eine Methode, die versucht, einen Datumsstring unter Berücksichtigung der Systemkultur zu erkennen.
string input = "19.06.2025";
DateTime parsed = DateTime.Parse(input);
Console.WriteLine(parsed); // 19.06.2025 00:00:00
Wenn der String ungültig ist, crasht das Programm mit einer Exception (niemand ist davor sicher!).
Kultur angeben
string input = "06/19/2025";
var enUS = new System.Globalization.CultureInfo("en-US");
DateTime dt = DateTime.Parse(input, enUS);
Console.WriteLine(dt); // 19.06.2025 00:00:00
Sicheres Parsen: TryParse
string input = "falsches datum";
bool ok = DateTime.TryParse(input, out DateTime safeDate);
if (!ok)
Console.WriteLine("Fehler: Datum konnte nicht erkannt werden!");
Striktes Format angeben: ParseExact und TryParseExact
var culture = System.Globalization.CultureInfo.InvariantCulture;
string dateStr = "2025-06-19";
DateTime d = DateTime.ParseExact(dateStr, "yyyy-MM-dd", culture);
Console.WriteLine(d); // 19.06.2025 00:00:00
bool parsedOk = DateTime.TryParseExact(
"19.06.2025",
"dd.MM.yyyy",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out DateTime myDate);
Tabelle beliebter Formate
| String | Format | Endobjekt |
|---|---|---|
| "2025-06-19" | "yyyy-MM-dd" | 19. Juni 2025 |
| "19.06.2025" | "dd.MM.yyyy" | 19. Juni 2025 |
| "06/19/2025" | "MM/dd/yyyy" | 19. Juni 2025 |
| "2025-06-19T14:15:16" | "s" | 19. Juni 2025 14:15:16 |
Arbeiten mit DateTimeStyles
Beim Parsen kannst du das Verhalten zusätzlich über den Parameter DateTimeStyles steuern. Dieses Enum erlaubt es dir, einzustellen, wie der Parser die Eingabedaten interpretieren soll. Zum Beispiel sorgt DateTimeStyles.AssumeUniversal dafür, dass die Zeit als UTC angenommen wird, wenn kein Offset angegeben ist. DateTimeStyles.AllowWhiteSpaces erlaubt es, überflüssige Leerzeichen im String zu ignorieren. Diese Einstellungen sind besonders praktisch, wenn du mit Daten aus externen Quellen arbeitest, bei denen das Format nicht immer vorhersehbar ist.
3. Formatierung und Parsen von DateOnly, TimeOnly
Die neuen Typen DateOnly und TimeOnly werden jetzt oft verwendet, um Daten/Zeit ohne unnötige Details zu speichern.
Formatierung
DateOnly birthday = new DateOnly(2000, 6, 19);
Console.WriteLine(birthday.ToString("dd MMMM yyyy")); // 19. Juni 2000
Parsen
var d = DateOnly.ParseExact("19.06.2000", "dd.MM.yyyy");
Console.WriteLine(d.Day); // 19
Genauso funktionieren die Methoden für TimeOnly (nur dass die Muster sich auf Stunden/Minuten/Sekunden beziehen):
TimeOnly t = TimeOnly.ParseExact("23:59", "HH:mm");
Console.WriteLine(t.Hour); // 23
Vorteile von DateOnly und TimeOnly
Die Verwendung von DateOnly und TimeOnly statt DateTime bringt einige wichtige Vorteile. Erstens ist es semantisch klarer – wenn du nur ein Datum ohne Zeit brauchst (z.B. Geburtsdatum), zeigt DateOnly diese Absicht deutlich. Zweitens hilft es, Probleme mit Zeitzonen zu vermeiden, die bei DateTime auftreten können. Drittens brauchen diese Typen weniger Speicherplatz in RAM und Datenbanken.
Formatierung und Parsen mit Zeitzonen
Wenn du Zeiten mit Offset speichern willst, nutze DateTimeOffset. Das ist besonders wichtig für internationale, verteilte Systeme. Alle Formatierungs- und Parse-Methoden funktionieren genauso, nur dass du jetzt auch das Offset steuern kannst:
DateTimeOffset meeting = new DateTimeOffset(2025, 6, 19, 17, 30, 0, TimeSpan.FromHours(3));
Console.WriteLine(meeting.ToString("o")); // 2025-06-19T17:30:00.0000000+03:00
string input = "2025-06-19T17:30:00+03:00";
var parsedOffset = DateTimeOffset.Parse(input);
Console.WriteLine(parsedOffset.Offset); // 03:00:00
4. Praktische Hinweise und typische Fehler
Eine der Fallen ist, beim Parsen internationaler Formate "Tag" und "Monat" zu verwechseln. Zum Beispiel ist der String "01/02/2025" in den USA der 2. Januar, in den meisten europäischen Ländern aber der 1. Februar (Überraschung!).
Oft wird auch vergessen, wie stark die Kultur Einfluss nimmt: Wenn die App auf einem Server in Deutschland läuft, aber User aus verschiedenen Ländern kommen, kann das Datumsformat aus der Datenbank auf jedem Server anders interpretiert werden.
Ein häufiger Fehler ist, .ToString() ohne Angabe von Kultur/Format für Logs und Datenaustausch zu verwenden: Das Ergebnis kann sich nach einer Migration auf ein anderes OS oder bei verschiedenen Windows-Usern ändern.
Tipps für die Arbeit mit Daten
- Für interne Speicherung und Datenaustausch immer die Invariant Culture (CultureInfo.InvariantCulture) oder explizit angegebene Formate verwenden.
- Für User-Interfaces die Kultur des Users nutzen oder ihm die Wahl des bevorzugten Formats lassen.
- Bei API- und Datenbankarbeit immer ISO 8601-Format bevorzugen, das ist internationaler Standard.
- Eingabedaten immer validieren: Existenz des Datums, Bereich und Plausibilität prüfen.
Arbeiten mit verschiedenen Datenquellen
Bei der Integration mit externen Systemen musst du oft mit Daten in verschiedenen Formaten arbeiten. Manche Systeme liefern Daten als Unix-Timestamp (Sekunden seit dem 1. Januar 1970), andere als Strings in nationalen Formaten. Es ist wichtig, sich vorher auf ein Austauschformat zu einigen und immer die Korrektheit des Parsings zu prüfen.
Außerdem solltest du daran denken, dass manche Formate mehrdeutig sein können. Zum Beispiel wird "12/13/2025" eindeutig als 13. Dezember 2025 interpretiert, aber "12/11/2025" kann je nach Kultur entweder der 12. November oder der 11. Dezember sein. In solchen Fällen ist es besser, weniger mehrdeutige Formate zu verwenden oder die Parsing-Kultur explizit anzugeben.
GO TO FULL VERSION