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

datetime2 vs datetimeoffset in SQL Server:qual è la differenza?

Questo articolo esamina le principali differenze tra datetime2 e datetimeoffset tipi di dati in SQL Server.

Entrambi i tipi di dati vengono utilizzati per memorizzare i valori di data e ora. Entrambi sono molto simili, ma con una differenza fondamentale; il datetimeoffset memorizza l'offset del fuso orario.

Ciò si traduce anche in datetimeoffset utilizzando più spazio di archiviazione di datetime2 , quindi utilizzeresti solo datetimeoffset se hai bisogno della differenza di fuso orario.

Ecco una tabella che delinea le differenze principali tra questi due tipi.

Funzione datetimeoffset datetime2
Conforme a SQL (ANSI e ISO 8601)
Intervallo di date 0001-01-01 a 9999-12-31 0001-01-01 a 9999-12-31
Intervallo di tempo 00:00:00 fino alle 23:59:59.9999999 00:00:00 fino alle 23:59:59.9999999
Lunghezza del personaggio 26 posizioni minimo
34 massimo
19 posizioni minimo
27 massimo
Dimensioni di archiviazione Da 8 a 10 byte, a seconda della precisione*

* Più 1 byte per memorizzare la precisione

Da 6 a 8 byte, a seconda della precisione*

* Più 1 byte per memorizzare la precisione

Precisione 100 nanosecondi 100 nanosecondi
Precisione frazionaria dei secondi
Precisione al secondo frazionario definita dall'utente
Intervallo di offset del fuso orario -14:00 a +14:00 Nessuno
Consapevolezza e conservazione della differenza di fuso orario No
Attenzione all'ora legale No No

Devo usare "datetime2" o "datetimeoffset"?

Ciò dipende dalla necessità o meno di includere un fuso orario.

Se devi includere una differenza di fuso orario, dovrai utilizzare datetimeoffset .

In caso contrario, utilizza datetime2 , poiché risparmierai spazio di archiviazione ed eliminerai potenziali problemi con un fuso orario (potenzialmente errato) nei tuoi dati.

Esempio 1 – Confronto di base

Ecco un rapido esempio per dimostrare la differenza fondamentale tra datetime2 e 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';

Risultato:

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

Qui ho impostato un datetime2 variabile allo stesso valore di datetimeoffset variabile. Questo fa sì che il valore venga convertito in datetime2 e possiamo quindi utilizzare un SELECT istruzione per vedere il valore di ciascuna variabile.

Entrambe le variabili utilizzano una scala di 7, il che significa che hanno 7 cifre decimali.

Quindi, in questo caso, l'unica differenza tra i due è che datetimeoffset il valore include l'offset del fuso orario e datetime2 il valore non lo fa.

Esempio 2 – Modifica della precisione

Entrambi i tipi consentono di specificare una precisione (utilizzando una scala compresa tra 0 e 7). Pertanto, è possibile impostare il datetime2 valore con una precisione inferiore a datetimeoffset valore (e viceversa).

Esempio:

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

Risultato:

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

Qui ho impostato il datetime2 valore su una scala di 3, il che significa che finisce con 3 cifre decimali invece di 7. In questo caso, i suoi secondi frazionari vengono arrotondati per eccesso (perché la cifra frazionaria successiva è 5 o superiore).

Quindi possiamo vedere che è possibile ottenere un valore di data/ora diverso a seconda dei secondi frazionari che assegniamo a datetime2 . Funziona anche nell'altro modo (ad es. se convertiamo da datetime2(7) a datetimeoffset(3) ).

Tuttavia, se riduciamo la parte frazionaria, non viene eseguito alcun arrotondamento:

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

Risultato:

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

Esempio 3 – Impostazione di valori da stringhe letterali

Negli esempi precedenti, datetime2 il valore è stato assegnato impostandolo sullo stesso valore di datetimeoffset valore. Quando lo facciamo, SQL Server esegue una conversione implicita in modo che i dati "si adattino" al nuovo tipo di dati.

Possiamo anche assegnare lo stesso valore direttamente a datetime2 variabile (anche se la documentazione ufficiale non afferma esplicitamente che accetta una stringa letterale con un offset di fuso orario):

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

Risultato:

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

Esempio 4 – Dimensioni di archiviazione

La dataora2 il tipo di dati utilizza due byte di spazio di archiviazione in meno rispetto a datetimeoffset per una data precisione.

La dataora2 può essere 6, 7 o 8 byte, a seconda della sua precisione.

Il datatimeoffset può essere 8, 9 o 10 byte, a seconda della sua precisione.

Microsoft afferma che datetime2 type utilizza anche 1 byte in più per memorizzare la sua precisione, nel qual caso utilizzerebbe almeno 3 byte in più rispetto a smalldatetime .

Questo vale anche per datetimeoffset (anche se non è esplicitamente indicato nella documentazione Microsoft).

Tuttavia, ciò dipende dal fatto che lo stiamo archiviando in una tabella o in una variabile e se lo stiamo convertendo o meno in una costante binaria.

Ecco cosa succede se utilizziamo DATALENGTH() funzione per restituire il numero di byte utilizzati per ciascuno dei nostri valori:

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

Risultato

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

Come previsto, 10 byte per datetimeoffset e 8 byte per datetime2 .

Ma se li convertiamo in varbinary , otteniamo quanto segue:

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

Risultato

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

Viene aggiunto un byte in più a ciascun valore per memorizzare la precisione.

Molti sviluppatori presumono che la conversione in varbinary è rappresentativo del modo in cui SQL Server archivia effettivamente i valori di data e ora. Tuttavia questo è vero solo in parte.

Sebbene sia vero che SQL Server archivia i valori di data e ora in formato esadecimale, tale valore esadecimale in realtà non include la precisione. Questo perché la precisione è inclusa nella definizione della colonna. Ma quando ci convertiamo in varbinary come abbiamo fatto nell'esempio precedente, la precisione è anteposta e questo aggiunge un byte in più.

Per maggiori dettagli su come questi tipi di dati vengono archiviati in contesti diversi, vedere i seguenti articoli:

  • Informazioni sulle dimensioni di archiviazione "datetimeoffset" in SQL Server
  • Informazioni sulle dimensioni di archiviazione "datetime2" in SQL Server