sql >> Database >  >> RDS >> Sqlserver

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

Dit artikel belicht de belangrijkste verschillen tussen de datetime en datetimeoffset gegevenstypen in SQL Server.

Beide gegevenstypen worden gebruikt voor het opslaan van datum- en tijdwaarden. Maar er zijn significante verschillen tussen de twee.

Het meest voor de hand liggende verschil is misschien wel dat de datetimeoffset slaat de tijdzone-offset op, terwijl datetime niet.

Een ander belangrijk verschil is dat datetimeoffset stelt u in staat de precisie te specificeren (tot 7 cijfers achter de komma). Dit betekent dat datetimeoffset waarden kunnen variëren in hun opslaggrootte, afhankelijk van de precisie die wordt gebruikt.

De datetime type daarentegen heeft een vaste opslaggrootte en precisie.

Over het algemeen moet u het gebruik van datetime . vermijden tenzij u een goede reden hebt om het te gebruiken (zoals ondersteuning van een legacy-systeem). Ook de datetime2 type komt beter overeen dan datetimeoffset , dus u kunt dat beter gebruiken als u geen tijdzoneverschuiving nodig heeft.

Hoe dan ook, hier is een tabel die datetime . vergelijkt en datetimeoffset :

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

* Plus 1 byte om de precisie in sommige gevallen op te slaan. Zie hieronder voor meer informatie.

8 bytes
Nauwkeurigheid 100 nanoseconden Afgerond op stappen van .000, .003 of .007 seconden
Door gebruiker gedefinieerde precisie van fractionele seconden Ja Nee
Tijdzoneverschuivingsbereik -14:00 tot +14:00 Geen
Bewustwording en behoud van tijdzoneverschuiving Ja Nee
Bewust zomertijd Nee Nee

Voorbeeld 1 – Basisvergelijking

In ieder geval, hier is een snel voorbeeld om het fundamentele verschil tussen datetime . aan te tonen en datetimeoffset .

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

Resultaat:

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

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

In dit geval is de datetimeoffset waarde omvat de tijdzone-offset en 7 decimalen. De datetime waarde aan de andere kant, omvat niet de tijdzone-offset en heeft slechts 3 decimalen. Bovendien wordt het derde breukcijfer naar boven afgerond. Dit komt omdat de nauwkeurigheid ervan altijd wordt afgerond op stappen van .000, .003 of .007 seconden.

Voorbeeld 2 – Waarden instellen op basis van tekenreeksen

In het vorige voorbeeld is de datetime 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" in het nieuwe gegevenstype.

Als we proberen dezelfde waarde rechtstreeks toe te wijzen aan de datetime variabele krijgen we een foutmelding:

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

Resultaat:

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

Dit komt omdat de datetime gegevenstype ondersteunt geen letterlijke tekenreeks met een tijdzone-offset. Het ondersteunt ook geen letterlijke tekenreeksen met meer dan 3 decimalen.

Dus als we de tijdzone-offset verwijderen, maar alle fractionele seconden behouden, krijgen we nog steeds een foutmelding:

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

Resultaat:

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

Om het te laten werken, moeten we een waarde toewijzen met niet meer dan 3 decimalen:

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

Resultaat:

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

Hoe dan ook, datetime heeft altijd een andere waarde dan datetimeoffset , omdat het de tijdzone-offset niet omvat. Dit geldt zelfs als we dezelfde precisie voor fractionele seconden en dezelfde waarde voor fractionele seconden gebruiken.

Om dit aan te tonen, is dit wat er gebeurt als we dezelfde waarde toewijzen aan 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';

Resultaat:

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

In dit geval datetimeoffset gebruikt een schaal van 3, wat het 3 decimalen geeft (hetzelfde als datetime ). Dit wordt gedaan met behulp van datetimeoffset(3) bij het declareren van de variabele.

Ik heb ook de fractionele seconden gewijzigd zodat datetime zou ze niet naar boven afronden (zodat beide waarden exact hetzelfde fractionele deel delen).

Hoe dan ook, datetimeoffset voegt nog steeds een tijdzone-offset toe, ingesteld op de standaardwaarde van +00:00.

Merk op dat mijn systeem nullen weergeeft op datetimeoffset 's breukdeel, maar de waarde gebruikt slechts 3 decimalen.

Voorbeeld 3 – Opslaggrootte

De datetime gegevenstype gebruikt 8 bytes.

De datetimeoffset gegevenstype gebruikt 8, 9 of 10 bytes, afhankelijk van de precisie.

Daarom bespaart u geen opslagcapaciteit door datetime . te gebruiken .

Als u echter een datetimeoffset waarde toe aan een binaire constante, voegt het 1 byte toe om precisie op te slaan.

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

Resultaat

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

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

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

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

Resultaat

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

Er wordt een extra byte toegevoegd aan de datetimeoffset waarde, maar niet naar de datetime waarde. Dit komt omdat de datetimeoffset waarde heeft een extra byte nodig om de precisie op te slaan (omdat de precisie door de gebruiker wordt gedefinieerd). De datetime waarde daarentegen heeft een vaste precisie, dus het is niet nodig om de precisie bij de waarde 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 bij het opslaan van datetimeoffset waarden. Dit komt omdat de precisie is opgenomen in de kolomdefinitie.

Voor meer informatie over hoe dit gegevenstype in de database wordt opgeslagen, zie 'datetimeoffset' Storage Size in SQL Server begrijpen.

Moet ik 'datetime' of 'datetimeoffset' gebruiken?

Als u een tijdzone-offset moet opnemen, moet u datetimeoffset . gebruiken . Zo niet, dan datetime kan voldoende zijn.

Microsoft raadt u echter aan om datetime2 . te gebruiken voor nieuw werk, omdat het veel voordelen heeft ten opzichte van datetime .

Zie datetime vs datetime2 voor een vergelijking van deze gegevenstypen.


  1. Varchar-veld numeriek sorteren in MySQL

  2. Een inleiding tot datamining

  3. Auto's verhuren is net zo eenvoudig als autorijden:een gegevensmodel voor een autoverhuurbedrijf

  4. Verwijderde 'root'-gebruiker en wachtwoord voor MySQL herstellen