Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

datetime vs datetimeoffset in SQL Server:Was ist der Unterschied?

Dieser Artikel hebt die Hauptunterschiede zwischen datetime hervor und datetimeoffset Datentypen in SQL Server.

Beide Datentypen werden zum Speichern von Datums- und Uhrzeitwerten verwendet. Aber es gibt signifikante Unterschiede zwischen den beiden.

Der vielleicht offensichtlichste Unterschied ist, dass der datetimeoffset speichert den Zeitzonenoffset, während datetime nicht.

Ein weiterer wichtiger Unterschied ist dieser datetimeoffset können Sie die Genauigkeit angeben (bis zu 7 Dezimalstellen). Das bedeutet, dass datetimeoffset Werte können je nach verwendeter Genauigkeit in ihrer Speichergröße variieren.

Die datetime type hingegen hat eine feste Speichergröße und Genauigkeit.

Im Allgemeinen sollten Sie die Verwendung von datetime vermeiden es sei denn, Sie haben einen guten Grund, es zu verwenden (z. B. die Unterstützung eines Legacy-Systems). Auch die datetime2 type ist eine genauere Übereinstimmung als datetimeoffset , also verwenden Sie das besser, wenn Sie keinen Zeitzonen-Offset benötigen.

So oder so, hier ist eine Tabelle, die datetime vergleicht und datetimeoffset :

Funktion datetimeoffset datetime
SQL-konform (ANSI &ISO 8601) Ja Nein
Zeitraum 0001-01-01 bis 9999-12-31 1753-01-01 bis 9999-12-31
Zeitbereich 00:00:00 bis 23:59:59.9999999 00:00:00 bis 23:59:59.997
Zeichenlänge mindestens 26 Positionen
höchstens 34
mindestens 19 Positionen
maximal 23
Speichergröße 8 bis 10 Bytes, je nach Genauigkeit*

* Plus 1 Byte, um in einigen Fällen die Genauigkeit zu speichern. Weitere Informationen finden Sie weiter unten.

8 Byte
Genauigkeit 100 Nanosekunden Gerundet auf 0,000, 0,003 oder 0,007 Sekunden
Benutzerdefinierte Genauigkeit für Sekundenbruchteile Ja Nein
Zeitzonenverschiebungsbereich -14:00 bis +14:00 Keine
Bewusstsein und Erhaltung der Zeitzonenverschiebung Ja Nein
Sommerzeit bewusst Nein Nein

Beispiel 1 – Grundlegender Vergleich

Auf jeden Fall ist hier ein kurzes Beispiel, um den grundlegenden Unterschied zwischen datetime zu demonstrieren und datetimeoffset .

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Ergebnis:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.557 |
+------------------------------------+-------------------------+

Hier setze ich eine datetime Variable auf den gleichen Wert wie datetimeoffset Variable. Dadurch wird der Wert in datetime konvertiert und wir können dann ein SELECT verwenden -Anweisung, um den Wert jeder Variablen anzuzeigen.

In diesem Fall das datetimeoffset Der Wert enthält den Zeitzonenoffset und 7 Dezimalstellen. Die datetime Wert hingegen enthält keinen Zeitzonen-Offset und hat nur 3 Dezimalstellen. Außerdem wird seine dritte Nachkommastelle aufgerundet. Dies liegt daran, dass die Genauigkeit immer auf 0,000, 0,003 oder 0,007 Sekunden gerundet wird.

Beispiel 2 – Setzen von Werten aus String-Literalen

Im vorherigen Beispiel die datetime value wurde zugewiesen, indem er auf den gleichen Wert wie datetimeoffset gesetzt wurde Wert. Wenn wir das tun, führt SQL Server eine implizite Konvertierung durch, damit die Daten dem neuen Datentyp „passen“.

Wenn wir versuchen, datetime den gleichen Wert direkt zuzuweisen Variable erhalten wir einen Fehler:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555 +07:30';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Ergebnis:

Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Das liegt daran, dass datetime Der Datentyp unterstützt kein Zeichenfolgenliteral mit einem Zeitzonenoffset. Außerdem werden keine Zeichenfolgenliterale mit mehr als 3 Dezimalstellen unterstützt.

Wenn wir also den Zeitzonenoffset entfernen, aber alle Sekundenbruchteile beibehalten, erhalten wir immer noch einen Fehler:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.5555555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Ergebnis:

Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Damit es funktioniert, müssen wir einen Wert mit nicht mehr als 3 Dezimalstellen zuweisen:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = '2025-05-21 10:15:30.555';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Ergebnis:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.557 |
+------------------------------------+-------------------------+

So oder so, datetime wird immer einen anderen Wert als datetimeoffset enthalten , da der Zeitzonenoffset nicht enthalten ist. Dies gilt auch dann, wenn wir die gleiche Sekundenbruchteil-Präzision und den gleichen Sekundenbruchteil-Wert verwenden.

Um dies zu demonstrieren, sehen Sie hier, was passiert, wenn wir datetimeoffset denselben Wert zuweisen :

DECLARE 
  @thedatetimeoffset datetimeoffset(3), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.123';
SET @thedatetime = '2025-05-21 10:15:30.123';
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime AS 'datetime';

Ergebnis:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime                |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.1230000 +00:00 | 2025-05-21 10:15:30.123 |
+------------------------------------+-------------------------+

In diesem Fall datetimeoffset verwendet eine Skala von 3, was 3 Dezimalstellen ergibt (dasselbe wie datetime ). Dies geschieht mit datetimeoffset(3) beim Deklarieren der Variablen.

Ich habe auch die Sekundenbruchteile so geändert, dass datetime würde sie nicht aufrunden (so dass beide Werte genau denselben Bruchteil haben).

Egal, datetimeoffset fügt dennoch einen Zeitzonenoffset hinzu, der auf den Standardwert +00:00 eingestellt ist.

Beachten Sie, dass mein System nachgestellte Nullen bei datetimeoffset anzeigt ’s Bruchteil, aber der Wert verwendet nur 3 Dezimalstellen.

Beispiel 3 – Speichergröße

Die datetime Datentyp verwendet 8 Bytes.

Der datetimeoffset Der Datentyp verwendet je nach Genauigkeit entweder 8, 9 oder 10 Bytes.

Daher sparen Sie keine Speichergröße, indem Sie datetime verwenden .

Wenn Sie jedoch ein datetimeoffset konvertieren Wert zu einer binären Konstante, fügt es 1 Byte hinzu, um die Genauigkeit zu speichern.

Folgendes passiert, wenn wir DATALENGTH() verwenden Funktion, um die Anzahl der Bytes zurückzugeben, die für jeden unserer Werte verwendet werden:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  DATALENGTH(@thedatetimeoffset) AS 'datetimeoffset',
  DATALENGTH(@thedatetime) AS 'datetime';

Ergebnis

+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 10               | 8          |
+------------------+------------+

Wie erwartet 10 Bytes für datetimeoffset und 8 Bytes für datetime .

Aber wenn wir sie in varbinary umwandeln , erhalten wir Folgendes:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime datetime;
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime = @thedatetimeoffset;
SELECT 
  DATALENGTH(CAST(@thedatetimeoffset AS varbinary(16))) AS 'datetimeoffset',
  DATALENGTH(CAST(@thedatetime AS varbinary(16))) AS 'datetime';

Ergebnis

+------------------+------------+
| datetimeoffset   | datetime   |
|------------------+------------|
| 11               | 8          |
+------------------+------------+

Dem datetimeoffset wird ein zusätzliches Byte hinzugefügt -Wert, aber nicht auf datetime Wert. Das liegt daran, dass der datetimeoffset value benötigt ein zusätzliches Byte zum Speichern der Genauigkeit (da die Genauigkeit benutzerdefiniert ist). Die datetime value hingegen hat eine feste Genauigkeit, sodass die Genauigkeit nicht mit dem Wert gespeichert werden muss.

Viele Entwickler gehen davon aus, dass die Konvertierung in varbinary ist repräsentativ dafür, wie SQL Server tatsächlich Datums- und Uhrzeitwerte speichert. Dies ist jedoch nur teilweise richtig.

Es stimmt zwar, dass SQL Server seine Datums- und Uhrzeitwerte im Hexadezimalformat speichert, aber dieser Hexadezimalwert enthält nicht wirklich die Genauigkeit beim Speichern von datetimeoffset Werte. Dies liegt daran, dass die Genauigkeit in der Spaltendefinition enthalten ist.

Weitere Einzelheiten dazu, wie dieser Datentyp in der Datenbank gespeichert wird, finden Sie unter Grundlegendes zur „datetimeoffset“-Speichergröße in SQL Server.

Soll ich „datetime“ oder „datetimeoffset“ verwenden?

Wenn Sie einen Zeitzonen-Offset einschließen müssen, müssen Sie datetimeoffset verwenden . Wenn nicht, dann datetime kann ausreichen.

Microsoft empfiehlt jedoch, dass Sie datetime2 verwenden für neue Arbeit, da es viele Vorteile gegenüber datetime hat .

Siehe datetime vs datetime2 für einen Vergleich dieser Datentypen.