sql >> Databasteknik >  >> RDS >> Sqlserver

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

Den här artikeln belyser de viktigaste skillnaderna mellan datetime och datumtidsförskjutning datatyper i SQL Server.

Båda datatyperna används för att lagra datum- och tidsvärden. Men det finns betydande skillnader mellan de två.

Den kanske mest uppenbara skillnaden är att datetime offset lagrar tidszonsförskjutningen, medan datetime inte.

En annan viktig skillnad är att datetimeoffset låter dig specificera precisionen (upp till 7 decimaler). Detta betyder att datetimeoffset värden kan variera i lagringsstorlek, beroende på vilken precision som används.

datetime typ å andra sidan har en fast lagringsstorlek och precision.

Generellt bör du undvika att använda datetime såvida du inte har en bra anledning att använda det (som att stödja ett äldre system). Även datetime2 typ är en närmare matchning än datetimeoffset , så det är bättre att använda det om du inte behöver en tidszonförskjutning.

Hur som helst, här är en tabell som jämför datumtid och datumtidsförskjutning :

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

* Plus 1 byte för att lagra precisionen i vissa fall. Se nedan för mer information.

8 byte
Noggrannhet 100 nanosekunder Avrundat till steg om 0,000, 0,003 eller 0,007 sekunder
Användardefinierad precision på bråkdelssekunder Ja Nej
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

Exempel 1 – Grundläggande jämförelse

Hur som helst, här är ett snabbt exempel för att visa den grundläggande skillnaden mellan datetime och datumtidsförskjutning .

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

Resultat:

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

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

I det här fallet, datetimeoffset värdet inkluderar tidszonförskjutningen och 7 decimaler. datetime värdet, å andra sidan, inkluderar inte tidszonförskjutningen och den har bara 3 decimaler. Dessutom avrundas dess tredje bråktalssiffra uppåt. Detta beror på att dess noggrannhet alltid avrundas till steg om 0,000, 0,003 eller 0,007 sekunder.

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

I föregående exempel, datetime 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.

Om vi ​​försöker tilldela samma värde direkt till datetime variabel får vi ett fel:

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

Resultat:

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

Detta beror på att datetime datatypen stöder inte en bokstavlig sträng med tidszonförskjutning. Dessutom stöder den inte strängliteraler med mer än 3 decimaler.

Så om vi tar bort tidszonförskjutningen, men behåller alla bråkdelar, får vi fortfarande ett felmeddelande:

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

Resultat:

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

För att få det att fungera måste vi tilldela ett värde med högst 3 decimaler:

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

Resultat:

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

Hur som helst, datetime kommer alltid att ha ett annat värde än datetimeoffset , eftersom det inte inkluderar tidszonsförskjutningen. Detta kommer att gälla även om vi använder samma bråksekundersprecision och bråksekundersvärde.

För att visa detta, här är vad som händer om vi tilldelar samma värde till datetimeoffset :

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

Resultat:

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

I det här fallet datetimeoffset använder en skala på 3, vilket ger den 3 decimaler (samma som datetime ). Detta görs med datetimeoffset(3) när variabeln deklareras.

Jag ändrade också bråkdelssekunderna så att datetime skulle inte avrunda dem (så att båda värdena delar exakt samma bråkdel).

Oavsett, datetime offset lägger fortfarande till en tidszonförskjutning, inställd på dess standardvärde på +00:00.

Observera att mitt system visar avslutande nollor vid datetimeoffset ’s bråkdel, men värdet använder bara 3 decimaler.

Exempel 3 – Lagringsstorlek

datetime datatypen använder 8 byte.

datetimeoffset datatypen använder antingen 8, 9 eller 10 byte, beroende på dess precision.

Därför sparar du ingen lagringsstorlek genom att använda datetime .

Men om du konverterar en datumtidsförskjutning värde till en binär konstant, lägger den till 1 byte för att lagra precision.

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), 
  @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';

Resultat

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

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

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

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

Resultat

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

En extra byte läggs till datetimeoffset värde men inte till datetime värde. Detta beror på att datetime offset värde behöver en extra byte för att lagra precisionen (eftersom precisionen är användardefinierad). datetime värde å andra sidan har en fast precision, så det finns inget behov av att precisionen lagras med värdet.

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 vid lagring av datetimeoffset värden. Det beror på att precisionen ingår i kolumndefinitionen.

För mer information om hur denna datatyp lagras i databasen, se Förstå lagringsstorleken för "datetimeoffset" i SQL Server.

Ska jag använda "datetime" eller "datetime offset"?

Om du behöver inkludera en tidszonförskjutning måste du använda datetimeoffset . Om inte, datetime kan räcka.

Microsoft rekommenderar dock att du använder datetime2 för nytt arbete, eftersom det har många fördelar över datetime .

Se datetime vs datetime2 för en jämförelse av dessa datatyper.


  1. SQLiteStatement kör en SELECT / INSERT / DELETE / UPDATE

  2. Exempel på att konvertera "tid" till "datumtid" i SQL Server (T-SQL)

  3. if (välj antal (kolumn) från tabellen)> 0 då

  4. Vad är SQL? Vad är en databas? Relationella databashanteringssystem (RDBMS) förklaras på vanlig engelska.