sql >> Database teknologi >  >> RDS >> Sqlserver

datetime vs datetimeoffset i SQL Server:Hvad er forskellen?

Denne artikel fremhæver de vigtigste forskelle mellem datetime og datotidsforskydning datatyper i SQL Server.

Begge datatyper bruges til lagring af dato- og tidsværdier. Men der er betydelige forskelle mellem de to.

Den måske mest åbenlyse forskel er, at datotidsforskydningen gemmer tidszoneforskydningen, mens datetime gør ikke.

En anden vigtig forskel er, at datetime offset giver dig mulighed for at angive præcisionen (op til 7 decimaler). Det betyder, at datetime offset værdier kan variere i deres lagerstørrelse, afhængigt af den anvendte præcision.

datoen type på den anden side har en fast opbevaringsstørrelse og præcision.

Generelt bør du undgå at bruge datetime medmindre du har en god grund til at bruge det (såsom at understøtte et ældre system). Også datetime2 type er et tættere match end datetime offset , så det er bedre at bruge det, hvis du ikke har brug for en tidszoneforskydning.

Uanset hvad, her er en tabel, der sammenligner datotid og datotidsforskydning :

Funktion datetime offset datotid
SQL-kompatibel (ANSI &ISO 8601) Ja Nej
Datointerval 0001-01-01 til 9999-12-31 1753-01-01 til 9999-12-31
Tidsinterval 00:00:00 til 23:59:59.9999999 00:00:00 til 23:59:59.997
Tegnlængde 26 positioner minimum
34 maksimum
19 positioner minimum
23 maksimum
Lagerstørrelse 8 til 10 bytes, afhængig af præcisionen*

* Plus 1 byte til at gemme præcisionen i nogle tilfælde. Se nedenfor for mere information.

8 bytes
Nøjagtighed 100 nanosekunder Afrundet til trin på 0,000, 003 eller 0,007 sekunder
Brugerdefineret brøksekundpræcision Ja Nej
Tidszoneforskydningsområde -14:00 til +14:00 Ingen
Opmærksomhed og bevarelse af tidszoneforskydning Ja Nej
Sommertid opmærksom på Nej Nej

Eksempel 1 – Grundlæggende sammenligning

Under alle omstændigheder er her et hurtigt eksempel til at demonstrere den grundlæggende forskel mellem datetime og datotidsforskydning .

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 |
+------------------------------------+-------------------------+

Her indstiller jeg et datotidspunkt variabel til samme værdi som datetime offset variabel. Dette får værdien til at blive konverteret til datetime og vi kan derefter bruge en SELECT sætning for at se værdien af ​​hver variabel.

I dette tilfælde er datetime offset værdien inkluderer tidszoneforskydningen og 7 decimaler. datoen værdien på den anden side inkluderer ikke tidszoneforskydningen, og den har kun 3 decimaler. Desuden rundes dets tredje brøkciffer op. Dette skyldes, at dens nøjagtighed altid er afrundet til trin på 0,000, 0,003 eller 0,007 sekunder.

Eksempel 2 – Indstilling af værdier fra strenge bogstaver

I det forrige eksempel er dato/klokkeslæt værdien blev tildelt ved at indstille den til den samme værdi som datetime offset værdi. Når vi gør det, udfører SQL Server en implicit konvertering for at dataene "passer" til den nye datatype.

Hvis vi forsøger at tildele den samme værdi direkte til datetime variabel får vi en fejl:

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.

Dette skyldes, at datetime datatypen understøtter ikke en streng-literal med en tidszoneforskydning. Den understøtter heller ikke strengliteraler med mere end 3 decimaler.

Så hvis vi fjerner tidszoneforskydningen, men beholder alle brøksekunderne, får vi stadig en fejl:

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.

For at få det til at fungere, skal vi tildele en værdi med højst 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 |
+------------------------------------+-------------------------+

Uanset hvad, datetime vil altid have en anden værdi end datetime offset , fordi den ikke inkluderer tidszoneforskydningen. Dette vil være sandt, selvom vi bruger den samme brøksekunderpræcision og brøksekunderværdi.

For at demonstrere dette, her er, hvad der sker, hvis vi tildeler den samme værdi til datetime offset :

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 dette tilfælde datetime offset bruger en skala fra 3, hvilket giver den 3 decimaler (det samme som datotid ). Dette gøres ved hjælp af datetimeoffset(3) når variablen erklæres.

Jeg ændrede også brøksekunderne, så datetime ville ikke runde dem op (så begge værdier deler nøjagtig den samme brøkdel).

Uanset hvad, datetime offset tilføjer stadig en tidszoneforskydning, sat til standardværdien på +00:00.

Bemærk, at mit system viser efterstillede nuller på datetime offset ’s brøkdel, men værdien bruger kun 3 decimaler.

Eksempel 3 – Lagerstørrelse

datoen datatypen bruger 8 bytes.

datotidsforskydningen datatypen bruger enten 8, 9 eller 10 bytes, afhængigt af dens præcision.

Derfor gemmer du ikke nogen lagerstørrelse ved at bruge datetime .

Men hvis du konverterer en datotidsforskydning værdi til en binær konstant, tilføjer den 1 byte for at gemme præcision.

Her er, hvad der sker, hvis vi bruger DATALENGTH() funktion til at returnere antallet af bytes brugt for hver af vores værdier:

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 forventet, 10 bytes til datetime offset og 8 bytes for datetime .

Men hvis vi konverterer dem til varbinary , får vi følgende:

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 ekstra byte føjes til datetime offset værdi, men ikke til datetime værdi. Dette skyldes, at datetime offset værdi har brug for en ekstra byte for at gemme præcisionen (fordi præcisionen er brugerdefineret). datoen værdi på den anden side har en fast præcision, så der er ikke behov for, at præcisionen skal gemmes med værdien.

Mange udviklere antager, at konvertering til varbinary er repræsentativ for, hvordan SQL Server faktisk gemmer dato- og tidsværdier. Dette er dog kun delvist sandt.

Selvom det er rigtigt, at SQL Server gemmer sine dato- og tidsværdier i hexadecimal, inkluderer denne hex-værdi faktisk ikke præcisionen ved lagring af datetime offset værdier. Dette skyldes, at præcisionen indgår i kolonnedefinitionen.

For flere detaljer om, hvordan denne datatype gemmes i databasen, se Forståelse af 'datetimeoffset'-lagerstørrelse i SQL Server.

Skal jeg bruge 'datetime' eller 'datetime offset'?

Hvis du skal inkludere en tidszoneforskydning, skal du bruge datetimeoffset . Hvis ikke, så datetime kan være tilstrækkeligt.

Microsoft anbefaler dog, at du bruger datetime2 til nyt arbejde, da det har mange fordele over datetime .

Se datetime vs datetime2 for en sammenligning af disse datatyper.


  1. Kan du bruge Microsoft Entity Framework med Oracle?

  2. Hvad virtuelle filstater gør, og ikke gør, fortæller dig om I/O-forsinkelse

  3. PostgreSQL-indeks på JSON

  4. Sådan formateres tal som valuta i MySQL