sql >> Databasteknik >  >> RDS >> Sqlserver

datetime2 vs datetimeoffset i SQL Server:Vad är skillnaden?

Den här artikeln tittar på de viktigaste skillnaderna mellan datetime2 och datumtidsförskjutning datatyper i SQL Server.

Båda datatyperna används för att lagra datum- och tidsvärden. Båda är väldigt lika, men med en nyckelskillnad; datetime offset lagrar tidszonsförskjutningen.

Detta resulterar också i datetimeoffset använder mer lagringsutrymme än datetime2 , så du skulle bara använda datetimeoffset om du behöver tidszonförskjutning.

Här är en tabell som beskriver de viktigaste skillnaderna mellan dessa två typer.

Funktion datumtidsförskjutning datetime2
SQL-kompatibel (ANSI &ISO 8601) Ja Ja
Datumintervall 0001-01-01 till 9999-12-31 0001-01-01 till 9999-12-31
Tidsintervall 00:00:00 till 23:59:59.9999999 00:00:00 till 23:59:59.9999999
Teckenlängd 26 positioner minst
34 max
19 positioner minst
27 max
Lagringsstorlek 8 till 10 byte, beroende på precisionen*

* Plus 1 byte för att lagra precisionen

6 till 8 byte, beroende på precisionen*

* Plus 1 byte för att lagra precisionen

Noggrannhet 100 nanosekunder 100 nanosekunder
Bråkdelssekundprecision Ja Ja
Användardefinierad precision på bråkdelssekunder Ja Ja
intervall för tidszonförskjutning -14:00 till +14:00 Inga
Medveten om och bevarande av tidszonförskjutning Ja Nej
Medveten om sommartid Nej Nej

Ska jag använda 'datetime2' eller 'datetimeoffset'?

Detta beror på om du behöver inkludera en tidszonsförskjutning eller inte.

Om du behöver inkludera en tidszonförskjutning måste du använda datetimeoffset .

Om inte, använd datetime2 , eftersom du sparar lagringsutrymme och eliminerar eventuella problem med att ha en (potentiellt fel) tidszonförskjutning i dina data.

Exempel 1 – Grundläggande jämförelse

Här är ett snabbt exempel för att visa den grundläggande skillnaden mellan datetime2 och datumtidsförskjutning .

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';

Resultat:

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

Här ställer jag in en datetime2 variabel till samma värde som datetimeoffset variabel. Detta gör att värdet konverteras till datetime2 och vi kan sedan använda en SELECT uttalande för att se värdet av varje variabel.

Båda variablerna använder en skala på 7, vilket innebär att de har 7 decimaler.

Så i det här fallet är den enda skillnaden mellan de två att datetimeoffset värdet inkluderar tidszonförskjutningen och datetime2 värde inte.

Exempel 2 – Ändra precisionen

Båda typerna låter dig ange en precision (genom att använda en skala mellan 0 och 7). Därför är det möjligt att ställa in datetime2 värde med en lägre precision än datetimeoffset värde (och vice versa).

Exempel:

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';

Resultat:

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

Här ställer jag in datetime2 värde till en skala av 3, vilket betyder att det slutar med 3 decimaler istället för 7. I det här fallet avrundas dess bråkdelssekunder uppåt (eftersom nästa bråksiffra är 5 eller högre).

Så vi kan se att det är möjligt att få ett annat datum/tidsvärde beroende på de bråkdelar som vi tilldelar datetime2 . Detta fungerar också åt andra hållet (t.ex. om vi konverterar från datetime2(7) till datetimeoffset(3) ).

Men om vi minskar bråkdelen utförs ingen avrundning:

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';

Resultat:

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

Exempel 3 – Ställa in värden från strängbokstaver

I de tidigare exemplen är datetime2 värdet tilldelades genom att sätta det till samma värde som datetimeoffset värde. När vi gör det utför SQL Server en implicit konvertering för att data ska "passa" till den nya datatypen.

Vi kan också tilldela samma värde direkt till datetime2 variabel (även om den officiella dokumentationen inte uttryckligen anger att den accepterar en bokstavlig sträng med en tidszonförskjutning):

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';

Resultat:

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

Exempel 4 – Förvaringsstorlek

datetime2 datatypen använder två byte mindre lagring än datetimeoffset för vilken precision som helst.

datetime2 kan vara antingen 6, 7 eller 8 byte, beroende på dess precision.

datetimeoffset kan vara antingen 8, 9 eller 10 byte, beroende på dess precision.

Microsoft uppger att datetime2 typ använder också 1 extra byte för att lagra sin precision, i vilket fall den skulle använda minst 3 byte mer än smalldatetime .

Detta gäller även för datetimeoffset (även om det inte uttryckligen anges i Microsofts dokumentation).

Det beror dock på om vi lagrar det i en tabell eller i en variabel, och om vi konverterar det till en binär konstant eller inte.

Här är vad som händer om vi använder DATALENGTH() funktion för att returnera antalet byte som används för vart och ett av våra värden:

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';

Resultat

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

Som förväntat, 10 byte för datetimeoffset och 8 byte för datetime2 .

Men om vi konverterar dem till varbinary , får vi följande:

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';

Resultat

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

En extra byte läggs till varje värde för att lagra precisionen.

Många utvecklare antar att konvertera till varbinary är representativt för hur SQL Server faktiskt lagrar datum- och tidsvärden. Detta är dock bara delvis sant.

Även om det är sant att SQL Server lagrar sina datum- och tidsvärden hexadecimalt, inkluderar det hexadecimala värdet faktiskt inte precisionen. Det beror på att precisionen ingår i kolumndefinitionen. Men när vi konverterar till varbinary precis som vi gjorde i det föregående exemplet är precisionen prependerad, och detta lägger till en extra byte.

För mer information om hur dessa datatyper lagras i olika sammanhang, se följande artiklar:

  • Förstå "datetimeoffset"-lagringsstorlek i SQL Server
  • Förstå lagringsstorleken "datetime2" i SQL Server

  1. Hur skapar jag loggfil i Oracle med PL/SQL?

  2. Komplex främmande nyckel-begränsning i SQLAlchemy

  3. Prestandamyter:Tabellvariabler finns alltid i minnet

  4. Säker TO_NUMBER()