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

datetime2 vs datetimeoffset i SQL Server:Hvad er forskellen?

Denne artikel ser på de vigtigste forskelle mellem datetime2 og datotidsforskydning datatyper i SQL Server.

Begge datatyper bruges til lagring af dato- og tidsværdier. Begge er meget ens, men med én nøgleforskel; datotidsforskydningen gemmer tidszoneforskydningen.

Dette resulterer også i datetime offset bruger mere lagerplads end datetime2 , så du ville kun bruge datetime offset hvis du har brug for tidszoneforskydning.

Her er en tabel, der skitserer de vigtigste forskelle mellem disse to typer.

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

* Plus 1 byte til at gemme præcisionen

6 til 8 bytes, afhængig af præcisionen*

* Plus 1 byte til at gemme præcisionen

Nøjagtighed 100 nanosekunder 100 nanosekunder
Brøksekundpræcision Ja Ja
Brugerdefineret brøksekundpræcision Ja Ja
Tidszoneforskydningsområde -14:00 til +14:00 Ingen
Opmærksomhed og bevarelse af tidszoneforskydning Ja Nej
Sommertid opmærksom på Nej Nej

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

Dette afhænger af, om du skal inkludere en tidszoneforskydning eller ej.

Hvis du skal inkludere en tidszoneforskydning, skal du bruge datetimeoffset .

Hvis ikke, så brug datetime2 , da du sparer lagerplads og eliminerer eventuelle problemer med at have en (potentielt forkert) tidszoneforskydning i dine data.

Eksempel 1 – Grundlæggende sammenligning

Her er et hurtigt eksempel til at demonstrere den grundlæggende forskel mellem datetime2 og datotidsforskydning .

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

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

Begge variabler bruger en skala fra 7, hvilket betyder, at de har 7 decimaler.

Så i dette tilfælde er den eneste forskel mellem de to, at datetime offset værdien inkluderer tidszoneforskydningen og datetime2 værdi ikke.

Eksempel 2 – Ændring af præcisionen

Begge typer giver dig mulighed for at angive en præcision (ved at bruge en skala mellem 0 og 7). Derfor er det muligt at indstille datetime2 værdi med en lavere præcision end datotidsforskydningen værdi (og omvendt).

Eksempel:

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

Her indstiller jeg datetime2 værdi til en skala fra 3, hvilket betyder, at den ender med 3 decimaler i stedet for 7. I dette tilfælde rundes dens brøksekunder op (fordi det næste brøkciffer er 5 eller højere).

Så vi kan se, at det er muligt at få en anden dato/tidsværdi afhængigt af de brøksekunder, som vi tildeler datetime2 . Dette fungerer også den anden vej (f.eks. hvis vi konverterer fra datetime2(7) til datetimeoffset(3) ).

Men hvis vi reducerer brøkdelen, udføres der ingen afrunding:

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

Eksempel 3 – Indstilling af værdier fra strenge bogstaver

I de foregående eksempler er datetime2 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.

Vi kan også tildele den samme værdi direkte til datetime2 variabel (selvom den officielle dokumentation ikke eksplicit angiver, at den accepterer en streng-literal med en tidszoneforskydning):

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

Eksempel 4 – Lagerstørrelse

datetime2 datatypen bruger to bytes mindre lagerplads end datetimeoffset for enhver given præcision.

datetime2 kan være enten 6, 7 eller 8 bytes, afhængigt af dens præcision.

datetime offset kan være enten 8, 9 eller 10 bytes, afhængigt af dens præcision.

Microsoft oplyser, at datetime2 type bruger også 1 ekstra byte for at gemme sin præcision, i hvilket tilfælde den ville bruge mindst 3 bytes mere end smalldatetime .

Dette gælder også for datetime offset (selvom det ikke er eksplicit angivet i Microsoft-dokumentationen).

Det afhænger dog af, om vi gemmer det i en tabel eller i en variabel, og om vi konverterer det til en binær konstant eller ej.

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

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

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 ekstra byte tilføjes til hver værdi for at gemme præcisionen.

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. Dette skyldes, at præcisionen indgår i kolonnedefinitionen. Men når vi konverterer til varbinary ligesom vi gjorde i det foregående eksempel, er præcisionen forudsat, og dette tilføjer en ekstra byte.

For flere detaljer om, hvordan disse datatyper gemmes i forskellige sammenhænge, ​​se følgende artikler:

  • Forståelse af 'datetimeoffset'-lagerstørrelse i SQL Server
  • Forståelse af 'datetime2'-lagerstørrelse i SQL Server

  1. Sådan løses ORA-06512 på linjenummer

  2. Hvordan cbrt() virker i PostgreSQL

  3. Importer XML-filer til PostgreSQL

  4. Fejlfinding, der løber tør for arbejdstråde