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) | Sì | Sì |
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 | Sì | Sì |
Precisione al secondo frazionario definita dall'utente | Sì | Sì |
Intervallo di offset del fuso orario | -14:00 a +14:00 | Nessuno |
Consapevolezza e conservazione della differenza di fuso orario | Sì | 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