Fortgeschrittene Arbeit mit Datum und Uhrzeit in C#: Von grundlegenden Operationen zu leistungsstarken Lösungen
\nDie Arbeit mit Datum und Uhrzeit gehört zu den häufigsten und gleichzeitig tückischsten Aufgaben in der Entwicklung. Ein Fehler in der Zeitzone oder eine falsche Formatierung kann zu schwerwiegenden Bugs in der Produktion führen. In diesem Artikel gehen wir über die grundlegenden Konstruktoren von DateTime hinaus und behandeln fortgeschrittene Techniken: DateTimeOffset, Arbeit mit Zeitzonen, hochpräzise Messungen mit Stopwatch sowie Fragen der Leistung und Threadsicherheit. Das Material richtet sich an Entwickler, die C# sicher beherrschen und zuverlässigen Code für .NET schreiben möchten.
1. DateTime, DateTimeOffset und TimeSpan: Den richtigen Typ wählen
\nViele Entwickler verwenden standardmäßig DateTime, aber in der modernen Welt verteilter Systeme ist dies oft nicht die beste Wahl. Betrachten wir die wichtigsten Unterschiede.
DateTime vs DateTimeOffset
\nDateTime speichert einen Zeitpunkt ohne explizite Bindung an eine Zeitzone. Sie können Kind (Local, Utc, Unspecified) angeben, aber dies ist nur ein Label, keine vollständige Information über den Offset. DateTimeOffset hingegen speichert immer den Offset von UTC, was es eindeutig und bevorzugt für die Speicherung in Datenbanken und APIs macht.
// DateTime — kann irreführend sein\nDateTime localNow = DateTime.Now; // Kind = Local\nDateTime utcNow = DateTime.UtcNow; // Kind = Utc\n\n// DateTimeOffset — immer expliziter Offset\nDateTimeOffset preciseNow = DateTimeOffset.Now; // +03:00 (Beispiel)\nDateTimeOffset utcOffset = DateTimeOffset.UtcNow; // +00:00\n\n// Konvertierung zwischen ihnen\nDateTimeOffset fromDateTime = new DateTimeOffset(2024, 12, 25, 10, 0, 0, TimeSpan.FromHours(3));\nConsole.WriteLine(fromDateTime.Offset); // 03:00:00\n\nEmpfehlung: Verwenden Sie DateTimeOffset zur Speicherung eines Zeitpunkts (z. B. Erstellungsdatum eines Datensatzes). Für die Anzeige in lokaler Zeit für den Benutzer konvertieren Sie auf der Präsentationsebene.
TimeSpan für Intervalle
\nTimeSpan speichert kein Datum, sondern nur einen Zeitraum. Es ist ein unverzichtbares Werkzeug für die Datumsarithmetik und die Messung der Dauer von Operationen.
DateTimeOffset start = DateTimeOffset.UtcNow;\n// ... irgendein langer Prozess ...\nDateTimeOffset end = DateTimeOffset.UtcNow;\n\nTimeSpan duration = end - start;\nConsole.WriteLine($"Die Operation dauerte {duration.TotalMilliseconds} ms");\n// Erstellen eines Intervalls\nTimeSpan workDay = new TimeSpan(8, 0, 0); // 8 Stunden\nDateTimeOffset deadline = DateTimeOffset.UtcNow.Add(workDay);\n\n\n2. Parsing und Formatierung: Kultur, ISO 8601 und Leistung
\nFehlerhaftes Parsing ist eine Quelle von Bugs in Anwendungen, die mit verschiedenen regionalen Einstellungen arbeiten. Betrachten wir fortgeschrittene Methoden.
\n\nParseExact und TryParseExact
\nVerwenden Sie ParseExact für Zeichenfolgen mit einem bekannten, strengen Format. Dies erhöht die Zuverlässigkeit und Lesbarkeit des Codes.
string dateString = "2024-12-25T10:30:00+03:00";\n// ISO 8601 — universelles Format\nDateTimeOffset parsed = DateTimeOffset.ParseExact(\n dateString,\n "yyyy-MM-dd'T'HH:mm:sszzz",\n CultureInfo.InvariantCulture\n);\nConsole.WriteLine(parsed); // 25.12.2024 10:30:00 +03:00\n\n// Sicheres Parsing mit TryParseExact\nif (DateTimeOffset.TryParseExact(\n "2024/12/25",\n new[] { "yyyy/MM/dd", "dd.MM.yyyy" },\n CultureInfo.InvariantCulture,\n DateTimeStyles.None,\n out DateTimeOffset result))\n{\n Console.WriteLine($"Erfolgreich geparst: {result}");\n}\n\nTipp: Verwenden Sie für die Speicherung von Daten in Logs und APIs immer das ISO 8601-Format ("o"-Spezifizierer). Dies garantiert eine eindeutige Lesbarkeit durch jedes System.
Formatierung unter Berücksichtigung der Kultur
\nBerücksichtigen Sie bei der Ausgabe für den Benutzer dessen Lokalisierung, verwenden Sie jedoch für den internen Austausch die invariante