sql >> Database >  >> RDS >> Sqlserver

datetime2 vs datetimeoffset in SQL Server:wat is het verschil?

Dit artikel gaat in op de belangrijkste verschillen tussen de datetime2 en datetimeoffset gegevenstypen in SQL Server.

Beide gegevenstypen worden gebruikt voor het opslaan van datum- en tijdwaarden. Beide lijken erg op elkaar, maar met één belangrijk verschil; de datetimeoffset slaat de tijdzone-offset op.

Dit resulteert ook in datetimeoffset meer opslagruimte gebruiken dan datetime2 , dus je zou alleen datetimeoffset . gebruiken als u de tijdzone-offset nodig heeft.

Hier is een tabel met de belangrijkste verschillen tussen deze twee typen.

Functie datetimeoffset datetime2
SQL-compatibel (ANSI &ISO 8601) Ja Ja
Datumbereik 0001-01-01 tot 9999-12-31 0001-01-01 tot 9999-12-31
Tijdbereik 00:00:00 tot 23:59:59,999999 00:00:00 tot 23:59:59,999999
Tekenlengte 26 posities minimaal
34 maximaal
19 posities minimaal
27 maximaal
Opslaggrootte 8 tot 10 bytes, afhankelijk van de precisie*

* Plus 1 byte om de precisie op te slaan

6 tot 8 bytes, afhankelijk van de precisie*

* Plus 1 byte om de precisie op te slaan

Nauwkeurigheid 100 nanoseconden 100 nanoseconden
Fractionele tweede precisie Ja Ja
Door gebruiker gedefinieerde precisie van fractionele seconden Ja Ja
Tijdzoneverschuivingsbereik -14:00 tot +14:00 Geen
Bewustwording en behoud van tijdzoneverschuiving Ja Nee
Bewust zomertijd Nee Nee

Moet ik 'datetime2' of 'datetimeoffset' gebruiken?

Dit hangt af van het feit of u al dan niet een tijdzone-offset moet opnemen.

Als u een tijdzone-offset moet opnemen, moet u datetimeoffset . gebruiken .

Zo niet, gebruik dan datetime2 , omdat u opslagruimte bespaart en mogelijke problemen met een (mogelijk verkeerde) tijdzoneverschuiving in uw gegevens elimineert.

Voorbeeld 1 – Basisvergelijking

Hier is een snel voorbeeld om het fundamentele verschil te demonstreren tussen datetime2 en 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';

Resultaat:

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

Hier stel ik een datetime2 in variabele naar dezelfde waarde als de datetimeoffset variabel. Hierdoor wordt de waarde geconverteerd naar datetime2 en we kunnen dan een SELECT . gebruiken statement om de waarde van elke variabele te zien.

Beide variabelen gebruiken een schaal van 7, wat betekent dat ze 7 cijfers achter de komma hebben.

Dus in dit geval is het enige verschil tussen de twee dat de datetimeoffset waarde omvat de tijdzone-offset en de datetime2 waarde niet.

Voorbeeld 2 – De precisie wijzigen

Met beide typen kunt u een precisie opgeven (door een schaal tussen 0 en 7 te gebruiken). Daarom is het mogelijk om de datetime2 . in te stellen waarde met een lagere precisie dan de datetimeoffset waarde (en vice versa).

Voorbeeld:

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

Resultaat:

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

Hier stel ik de datetime2 . in waarde naar een schaal van 3, wat betekent dat het eindigt met 3 decimalen in plaats van 7. In dit geval worden de fracties van seconden naar boven afgerond (omdat het volgende fractionele cijfer 5 of hoger is).

We kunnen dus zien dat het mogelijk is om een ​​andere datum/tijd-waarde te krijgen, afhankelijk van de fractionele seconden die we toewijzen aan datetime2 . Dit werkt ook andersom (bijv. als we converteren van datetime2(7) naar datetimeoffset(3) ).

Als we echter het breukdeel verkleinen, wordt er niet afgerond:

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

Resultaat:

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

Voorbeeld 3 – Waarden instellen uit String Literals

In de vorige voorbeelden is de datetime2 waarde is toegewezen door deze op dezelfde waarde in te stellen als de datetimeoffset waarde. Wanneer we dat doen, voert SQL Server een impliciete conversie uit zodat de gegevens "passen" bij het nieuwe gegevenstype.

We kunnen dezelfde waarde ook rechtstreeks toewijzen aan de datetime2 variabele (hoewel de officiële documentatie niet expliciet vermeldt dat het een letterlijke tekenreeks accepteert met een tijdzone-offset):

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

Resultaat:

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

Voorbeeld 4 – Opslaggrootte

De datetime2 gegevenstype gebruikt twee bytes minder opslagruimte dan datetimeoffset voor elke gegeven precisie.

De datetime2 kan 6, 7 of 8 bytes zijn, afhankelijk van de nauwkeurigheid.

De datetimeoffset kan 8, 9 of 10 bytes zijn, afhankelijk van de nauwkeurigheid.

Microsoft stelt dat de datetime2 type gebruikt ook 1 extra byte om de precisie op te slaan, in welk geval het minstens 3 bytes meer zou gebruiken dan smalldatetime .

Dit geldt ook voor datetimeoffset (ook al wordt dit niet expliciet vermeld in de Microsoft-documentatie).

Dat hangt er echter van af of we het in een tabel of in een variabele opslaan en of we het al dan niet naar een binaire constante converteren.

Dit is wat er gebeurt als we de DATALENGTH() . gebruiken functie om het aantal bytes terug te geven dat voor elk van onze waarden is gebruikt:

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

Resultaat

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

Zoals verwacht, 10 bytes voor datetimeoffset en 8 bytes voor datetime2 .

Maar als we ze converteren naar varbinary , krijgen we het volgende:

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

Resultaat

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

Aan elke waarde wordt een extra byte toegevoegd om de precisie op te slaan.

Veel ontwikkelaars gaan ervan uit dat het converteren naar varbinary is representatief voor hoe SQL Server de datum- en tijdwaarden daadwerkelijk opslaat. Dit is echter slechts gedeeltelijk waar.

Hoewel het waar is dat SQL Server de datum- en tijdwaarden in hexadecimaal opslaat, bevat die hexadecimale waarde eigenlijk niet de precisie. Dit komt omdat de precisie is opgenomen in de kolomdefinitie. Maar wanneer we converteren naar varbinary zoals we deden in het vorige voorbeeld, wordt de precisie toegevoegd, en dit voegt een extra byte toe.

Zie de volgende artikelen voor meer informatie over hoe deze gegevenstypen in verschillende contexten worden opgeslagen:

  • Inzicht in de opslaggrootte van 'datetimeoffset' in SQL Server
  • Inzicht in de opslaggrootte van 'datetime2' in SQL Server

  1. Een lijst<> invoegen in de SQL Server-tabel

  2. Hoe importeer ik modules of installeer ik extensies in PostgreSQL 9.1+?

  3. Wat zijn de 6 belangrijkste componenten van Microsoft Access?

  4. Hoe lege spaties in null-waarden om te zetten met behulp van SQL Server?