Datum und Zeit in SQL Server richtig zu speichern und abzufragen, ist wichtig für korrekte Berichte, zuverlässige Protokolle und genaue Auswertungen. Die Datentypen date, datetime2 und datetimeoffset sehen ähnlich aus, bilden aber unterschiedliche Informationen ab. Dieser Beitrag zeigt, welcher Typ zu welchem Zweck passt und wie du Zeiträume sicher filterst.

Wenn du dich zunächst mit den Grundlagen der Datenbanksprache vertraut machen möchtest, lies auch die Einführung in SQL. Wie Daten sinnvoll strukturiert werden, erklärt der Beitrag Normalisierung von Datenbanken bis zur 3. Normalform.

Welcher Datentyp passt für Datum und Zeit in SQL Server?

Wähle den Datentyp danach aus, welche Information deine Anwendung tatsächlich benötigt. Ein Lieferdatum braucht meist keine Uhrzeit. Ein protokollierter Zeitpunkt braucht dagegen mindestens Datum und Uhrzeit. Bei Ereignissen aus verschiedenen Zeitzonen spielt zusätzlich der Bezug zu UTC eine Rolle.

Datentyp Enthält Zeitzonenbezug Typischer Einsatz
date Jahr, Monat und Tag Nein Geburtstag, Lieferdatum, Buchungstag
datetime2 Datum und Uhrzeit mit bis zu sieben Nachkommastellen Nein Zeitpunkte, wenn die Zeitzone separat geregelt ist oder alle Werte UTC darstellen
datetimeoffset Datum, Uhrzeit und Offset zu UTC Ja, als Offset Zeitpunkte, bei denen der UTC-Offset mit dem Wert erhalten bleiben soll

date für reine Kalenderdaten

Der Datentyp date speichert nur ein Kalenderdatum im Bereich von 0001-01-01 bis 9999-12-31. Er belegt drei Byte. Eine Uhrzeit oder Zeitzone gehört nicht dazu.

Verwende date für Angaben wie den Geburtstag einer Person, das Datum einer Lieferung oder den Tag einer Rechnung. Damit vermeidest du, dass fachlich bedeutungslose Uhrzeiten wie Mitternacht in der Tabelle stehen.

datetime2 für Datum und Uhrzeit

datetime2 speichert Datum und Uhrzeit. Die Genauigkeit lässt sich mit einer Nachkommastellen-Angabe von 0 bis 7 festlegen. Der Standardwert ist datetime2(7); je nach Genauigkeit benötigt der Datentyp sechs bis acht Byte.

Der Typ enthält keinen Zeitzonen-Offset. Eine Spalte namens ErfasstAmUtc kann also UTC-Zeitwerte enthalten, aber SQL Server erkennt das nicht am Datentyp. Die Bedeutung „UTC“ ist in diesem Fall eine Vereinbarung, die deine Anwendung und Datenbank konsequent einhalten müssen.

datetimeoffset für einen Zeitpunkt mit UTC-Offset

datetimeoffset ergänzt Datum und Uhrzeit um einen Offset zu UTC, zum Beispiel +01:00 oder -05:00. SQL Server bewahrt diesen Offset beim Speichern auf und verarbeitet Vergleiche und Sortierungen anhand des UTC-Zeitpunkts.

Ein Offset ist aber keine vollständige Zeitzone. Der Wert +01:00 enthält weder einen Ortsnamen noch Regeln für Sommerzeit oder historische Änderungen. Wenn eine Anwendung dauerhaft eine lokale Zeitzone wie „Mitteleuropäische Zeit“ berücksichtigen muss, speichere den Zeitzonennamen bei Bedarf zusätzlich.

Datum und Zeit in SQL Server sicher als Werte übergeben

Mehrdeutige Datumsangaben wie 03/04/2026 können je nach Gebietsschema als 3. April oder 4. März gelesen werden. Die Einstellungen SET LANGUAGE und SET DATEFORMAT beeinflussen, wie SQL Server bestimmte Zeichenfolgen interpretiert.

Nutze in Anwendungen möglichst typisierte Parameter, zum Beispiel einen Parameter vom Typ datetime2, statt Datumswerte in SQL-Zeichenfolgen einzubauen. Für feste Werte in T-SQL sind ISO-8601-Angaben mit dem Buchstaben T bei Datum und Uhrzeit eindeutig:

DECLARE @Zeitpunkt datetime2(7) = '2026-04-03T14:25:00.1234567';
DECLARE @OffsetZeitpunkt datetimeoffset(7) = '2026-04-03T14:25:00.1234567+02:00';
DECLARE @Kalendertag date = DATEFROMPARTS(2026, 4, 3);

Für programmgesteuerte Abfragen sollten Parameter denselben SQL-Datentyp wie die verglichene Spalte haben. So vermeidest du unnötige Umwandlungen und senkst das Risiko, dass eine Zeichenfolge anders interpretiert wird als erwartet.

Zeiträume mit einer offenen Obergrenze filtern

Ein häufiger Fehler ist, für einen ganzen Tag eine Obergrenze wie 23:59:59 anzugeben. Damit können Werte mit Nachkommastellen am Tagesende fehlen. Außerdem hängt ein Wert wie 23:59:59.997 von der Genauigkeit eines alten Datentyps ab.

Verwende stattdessen eine inklusive Untergrenze und eine exklusive Obergrenze: größer oder gleich Beginn und kleiner als Beginn des nächsten Zeitraums. So erfasst die Abfrage jeden passenden Zeitpunkt, unabhängig von der gespeicherten Nachkommastellen-Genauigkeit.

Einen einzelnen Tag abfragen

Im folgenden Beispiel wird der 3. April 2026 vollständig ausgewählt. Die obere Grenze ist Mitternacht des Folgetages und gehört nicht mehr zum gesuchten Zeitraum.

DECLARE @Tag date = DATEFROMPARTS(2026, 4, 3);
DECLARE @Von datetime2(7) = CONVERT(datetime2(7), @Tag);
DECLARE @BisExklusiv datetime2(7) = DATEADD(day, 1, @Von);

SELECT EreignisId, ErfasstAmUtc
FROM dbo.Ereignis
WHERE ErfasstAmUtc >= @Von
  AND ErfasstAmUtc < @BisExklusiv;

Ist die Spalte selbst vom Typ date, kannst du auch mit Datumswerten als Grenzen arbeiten. Verwende weiterhin den Beginn des Folgetages als exklusive Grenze:

DECLARE @Tag date = DATEFROMPARTS(2026, 4, 3);
DECLARE @BisExklusiv date = DATEADD(day, 1, @Tag);

SELECT Lieferdatum
FROM dbo.Bestellung
WHERE Lieferdatum >= @Tag
  AND Lieferdatum < @BisExklusiv;

Einen Monat abfragen

Für einen ganzen Monat berechnest du den ersten Tag des Monats und addierst einen Monat. Im Beispiel umfasst der Filter den April 2026, einschließlich aller Uhrzeiten am 30. April.

DECLARE @Von datetime2(7) =
    CONVERT(datetime2(7), DATEFROMPARTS(2026, 4, 1));

DECLARE @BisExklusiv datetime2(7) = DATEADD(month, 1, @Von);

SELECT EreignisId, ErfasstAmUtc
FROM dbo.Ereignis
WHERE ErfasstAmUtc >= @Von
  AND ErfasstAmUtc < @BisExklusiv;

Ein Jahr abfragen

Auch Jahresfilter lassen sich aus zwei Jahresgrenzen bilden. Für das Jahr 2026 reicht der Bereich vom 1. Januar 2026 bis unmittelbar vor dem 1. Januar 2027.

DECLARE @Jahr int = 2026;

DECLARE @Von datetime2(7) =
    CONVERT(datetime2(7), DATEFROMPARTS(@Jahr, 1, 1));

DECLARE @BisExklusiv datetime2(7) = DATEADD(year, 1, @Von);

SELECT EreignisId, ErfasstAmUtc
FROM dbo.Ereignis
WHERE ErfasstAmUtc >= @Von
  AND ErfasstAmUtc < @BisExklusiv;

BETWEEN schließt beide Grenzen ein. Bei einer Datum-Uhrzeit-Spalte endet eine Abfrage mit BETWEEN @Von AND @Bis daher genau am angegebenen Zeitpunkt von @Bis. Ist @Bis Mitternacht, fehlen die übrigen Zeitpunkte dieses Tages. Eine exklusive Obergrenze macht die Absicht klar und lässt sich gut mit einem Index auf der Zeitspalte kombinieren.

UTC, lokale Uhrzeit und Sommerzeit richtig behandeln

UTC bietet eine gemeinsame Zeitbasis für Anwendungen, die an mehreren Standorten laufen. Für UTC-Zeitwerte ohne gespeicherten Offset eignet sich datetime2, sofern die Anwendung die UTC-Konvention konsequent einhält. SYSUTCDATETIME() liefert einen UTC-Wert vom Typ datetime2.

DECLARE @JetztUtc datetime2(7) = SYSUTCDATETIME();

GETDATE() liefert dagegen ein datetime ohne Offset. Die Funktion gibt die Zeit des SQL-Server-Computers zurück. Sie verrät deshalb nicht, welche Zeitzone der Wert repräsentiert. SYSDATETIMEOFFSET() liefert Datum, Uhrzeit und den Offset des Computers; bei SYSUTCDATETIME() ist der Wert ausdrücklich UTC.

Für Berichte nach einem lokalen Kalendertag solltest du zuerst die Grenzen in der gewünschten Zeitzone festlegen und beide Grenzen anschließend nach UTC umrechnen. Addiere nicht pauschal 24 Stunden auf eine UTC-Grenze: Bei einer Zeitumstellung kann ein lokaler Tag 23 oder 25 Stunden umfassen.

DECLARE @LokalVon datetime2(7) = '2026-03-29T00:00:00';
DECLARE @LokalBis datetime2(7) = DATEADD(day, 1, @LokalVon);

DECLARE @VonUtc datetime2(7) =
    CONVERT(datetime2(7),
        @LokalVon AT TIME ZONE 'Central European Standard Time'
                  AT TIME ZONE 'UTC');

DECLARE @BisUtc datetime2(7) =
    CONVERT(datetime2(7),
        @LokalBis AT TIME ZONE 'Central European Standard Time'
                  AT TIME ZONE 'UTC');

SELECT EreignisId, ErfasstAmUtc
FROM dbo.Ereignis
WHERE ErfasstAmUtc >= @VonUtc
  AND ErfasstAmUtc < @BisUtc;

AT TIME ZONE verwendet Zeitzonenregeln, einschließlich Sommerzeit. Bei der Umstellung auf Sommerzeit gibt es örtliche Uhrzeiten, die übersprungen werden. Bei der Rückstellung auf Winterzeit kommen Uhrzeiten doppelt vor. SQL Server löst solche Fälle nach den Regeln der angegebenen Zeitzone auf. Prüfe daher besonders sorgfältig, ob deine Anwendung mehrdeutige lokale Zeitpunkte selbst behandeln muss.

Implizite Konvertierungen vermeiden

Wenn ein Ausdruck unterschiedliche Datentypen kombiniert, wandelt SQL Server den Typ mit der niedrigeren Priorität in den Typ mit der höheren Priorität um. Bei den hier besprochenen Typen gilt: datetimeoffset hat höhere Priorität als datetime2, und datetime2 hat höhere Priorität als date.

Das kann zu unerwarteten Ergebnissen führen, wenn zum Beispiel eine datetime2-Spalte mit einem datetimeoffset-Parameter verglichen wird. SQL Server kann einen Wert umwandeln, obwohl im Code keine Umwandlung steht. Ein fehlender Offset wird dabei nicht automatisch aus dem Standort des Nutzers abgeleitet. Übergib deshalb Parameter mit einem passenden Typ und kläre ausdrücklich, ob die Werte UTC oder Ortszeit darstellen.

Wende außerdem möglichst keine Funktion auf die gefilterte Spalte an. Dieser Filter muss den gespeicherten Wert für jede Zeile in ein Datum umwandeln:

WHERE CONVERT(date, ErfasstAmUtc) = @Tag

Die Bereichsvariante vergleicht dagegen die Spalte direkt mit zwei Grenzen:

WHERE ErfasstAmUtc >= @Von
  AND ErfasstAmUtc < @BisExklusiv

Funktionen oder Konvertierungen auf Spalten können die Nutzung eines Index erschweren. Ob SQL Server einen Index verwendet, hängt auch von den vorhandenen Indizes und dem Ausführungsplan ab. Prüfe den Plan, wenn ein Filter unerwartet langsam läuft.

Eine praktische Faustregel

  • Nutze date, wenn die Uhrzeit keine fachliche Bedeutung hat.
  • Nutze datetime2 für Datum und Uhrzeit ohne gespeicherten Offset. Dokumentiere klar, ob die Werte UTC oder lokale Zeit darstellen.
  • Nutze datetimeoffset, wenn der Offset zum Zeitpunkt mitgespeichert werden soll. Ergänze bei Bedarf den Namen der maßgeblichen Zeitzone.
  • Filtere Zeiträume mit >= Beginn und < Beginn des Folgezeitraums.
  • Verwende typisierte Parameter und eindeutige ISO-8601-Werte statt mehrdeutiger Datumszeichenfolgen.

Für neue Tabellen ist datetime in der Regel nicht mehr die erste Wahl. datetime2 bietet einen größeren Wertebereich und eine einstellbare Genauigkeit. Entscheidend bleibt, dass Datenbank, Anwendung und Berichte dieselbe Vereinbarung zu UTC und lokalen Zeitzonen verwenden.

Technische Quellen

Werbung / Affiliate-Links: Die mit einem Sternchen (*) gekennzeichneten Links sind Amazon-Partnerlinks. Wenn du darüber etwas kaufst, erhalte ich möglicherweise eine Provision. Für dich entstehen dadurch keine zusätzlichen Kosten. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen.