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

datetime2 vs. datetimeoffset in SQL Server:Was ist der Unterschied?

Dieser Artikel befasst sich mit den Hauptunterschieden zwischen datetime2 und datetimeoffset Datentypen in SQL Server.

Beide Datentypen werden zum Speichern von Datums- und Uhrzeitwerten verwendet. Beide sind sehr ähnlich, aber mit einem entscheidenden Unterschied; der datetimeoffset speichert den Zeitzonenoffset.

Dies führt auch zu datetimeoffset verwendet mehr Speicherplatz als datetime2 , also würden Sie nur datetimeoffset verwenden wenn Sie den Zeitzonen-Offset benötigen.

Hier ist eine Tabelle, die die Hauptunterschiede zwischen diesen beiden Typen umreißt.

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

* Plus 1 Byte zum Speichern der Genauigkeit

6 bis 8 Byte, je nach Genauigkeit*

* Plus 1 Byte zum Speichern der Genauigkeit

Genauigkeit 100 Nanosekunden 100 Nanosekunden
Präzision auf Sekundenbruchteile Ja Ja
Benutzerdefinierte Genauigkeit für Sekundenbruchteile Ja Ja
Zeitzonenverschiebungsbereich -14:00 bis +14:00 Keine
Bewusstsein und Erhaltung der Zeitzonenverschiebung Ja Nein
Sommerzeit bewusst Nein Nein

Soll ich „datetime2“ oder „datetimeoffset“ verwenden?

Dies hängt davon ab, ob Sie einen Zeitzonenoffset einbeziehen müssen oder nicht.

Wenn Sie einen Zeitzonen-Offset einschließen müssen, müssen Sie datetimeoffset verwenden .

Wenn nicht, verwenden Sie datetime2 , da Sie Speicherplatz sparen und potenzielle Probleme mit einem (möglicherweise falschen) Zeitzonenoffset in Ihren Daten beseitigen.

Beispiel 1 – Grundlegender Vergleich

Hier ist ein kurzes Beispiel, um den grundlegenden Unterschied zwischen datetime2 zu demonstrieren und datetimeoffset .

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

Ergebnis:

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

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

Beide Variablen verwenden eine Skala von 7, was bedeutet, dass sie 7 Dezimalstellen haben.

In diesem Fall besteht der einzige Unterschied zwischen den beiden darin, dass der datetimeoffset Der Wert enthält den Zeitzonenoffset und datetime2 Wert nicht.

Beispiel 2 – Ändern der Genauigkeit

Bei beiden Typen können Sie eine Genauigkeit angeben (indem Sie eine Skala zwischen 0 und 7 verwenden). Daher ist es möglich, datetime2 festzulegen Wert auf eine niedrigere Genauigkeit als datetimeoffset Wert (und umgekehrt).

Beispiel:

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

Ergebnis:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime2               |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 +07:30 | 2025-05-21 10:15:30.556 |
+------------------------------------+-------------------------+

Hier setze ich das datetime2 Wert auf eine Skala von 3, was bedeutet, dass er am Ende 3 Dezimalstellen statt 7 hat. In diesem Fall werden seine Sekundenbruchteile aufgerundet (weil die nächste Nachkommastelle 5 oder höher ist).

Wir können also sehen, dass es möglich ist, einen anderen Datums-/Uhrzeitwert zu erhalten, abhängig von den Bruchteilen von Sekunden, die wir datetime2 zuweisen . Dies funktioniert auch in die andere Richtung (z. B. wenn wir von datetime2(7) konvertieren zu datetimeoffset(3) ).

Wenn wir jedoch den Bruchteil reduzieren, wird keine Rundung durchgeführt:

DECLARE 
  @thedatetimeoffset datetimeoffset(7), 
  @thedatetime2 datetime2(3);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5554444 +07:30';
SET @thedatetime2 = @thedatetimeoffset;
SELECT 
  @thedatetimeoffset AS 'datetimeoffset',
  @thedatetime2 AS 'datetime2';

Ergebnis:

+------------------------------------+-------------------------+
| datetimeoffset                     | datetime2               |
|------------------------------------+-------------------------|
| 2025-05-21 10:15:30.5554444 +07:30 | 2025-05-21 10:15:30.555 |
+------------------------------------+-------------------------+

Beispiel 3 – Setzen von Werten aus String-Literalen

In den vorherigen Beispielen wurde datetime2 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“.

Wir können den gleichen Wert auch direkt datetime2 zuweisen Variable (auch wenn die offizielle Dokumentation nicht explizit angibt, dass sie ein String-Literal mit einem Zeitzonen-Offset akzeptiert):

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

Ergebnis:

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

Beispiel 4 – Speichergröße

Die datetime2 Der Datentyp benötigt zwei Bytes weniger Speicherplatz als datetimeoffset für jede gegebene Genauigkeit.

Die datetime2 kann je nach Genauigkeit entweder 6, 7 oder 8 Byte groß sein.

Der datetimeoffset kann je nach Genauigkeit entweder 8, 9 oder 10 Byte groß sein.

Microsoft gibt an, dass die datetime2 type verwendet auch 1 zusätzliches Byte, um seine Genauigkeit zu speichern, in diesem Fall würde es mindestens 3 Bytes mehr als smalldatetime verwenden .

Dies gilt auch für datetimeoffset (auch wenn es nicht ausdrücklich in der Microsoft-Dokumentation angegeben ist).

Das hängt jedoch davon ab, ob wir es in einer Tabelle oder in einer Variablen speichern und ob wir es in eine binäre Konstante konvertieren oder nicht.

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), 
  @thedatetime2 datetime2(7);
SET @thedatetimeoffset = '2025-05-21 10:15:30.5555555 +07:30';
SET @thedatetime2 = @thedatetimeoffset;
SELECT 
  DATALENGTH(@thedatetimeoffset) AS 'datetimeoffset',
  DATALENGTH(@thedatetime2) AS 'datetime2';

Ergebnis

+------------------+-------------+
| datetimeoffset   | datetime2   |
|------------------+-------------|
| 10               | 8           |
+------------------+-------------+

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

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

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

Ergebnis

+------------------+-------------+
| datetimeoffset   | datetime2   |
|------------------+-------------|
| 11               | 9           |
+------------------+-------------+

Jedem Wert wird ein zusätzliches Byte hinzugefügt, um die Genauigkeit zu speichern.

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 Zeitwerte im Hexadezimalformat speichert, aber dieser Hexadezimalwert enthält nicht wirklich die Genauigkeit. Dies liegt daran, dass die Genauigkeit in der Spaltendefinition enthalten ist. Aber wenn wir in varbinary konvertieren Wie im vorherigen Beispiel wird die Genauigkeit vorangestellt, und dies fügt ein zusätzliches Byte hinzu.

Weitere Einzelheiten darüber, wie diese Datentypen in verschiedenen Kontexten gespeichert werden, finden Sie in den folgenden Artikeln:

  • Verstehen der „datetimeoffset“-Speichergröße in SQL Server
  • Informationen zur Speichergröße „datetime2“ in SQL Server