sql >> Base de Datos >  >> RDS >> Sqlserver

datetime2 vs datetimeoffset en SQL Server:¿Cuál es la diferencia?

Este artículo analiza las principales diferencias entre datetime2 y desplazamiento de fecha y hora tipos de datos en SQL Server.

Ambos tipos de datos se utilizan para almacenar valores de fecha y hora. Ambos son muy similares, pero con una diferencia clave; el desplazamiento de fecha y hora almacena el desplazamiento de la zona horaria.

Esto también da como resultado datetimeoffset utilizando más espacio de almacenamiento que datetime2 , por lo que solo usaría datetimeoffset si necesita la compensación de la zona horaria.

Aquí hay una tabla que describe las diferencias clave entre estos dos tipos.

Característica datetimeoffset fechahora2
Cumple con SQL (ANSI e ISO 8601)
Intervalo de fechas 0001-01-01 a 9999-12-31 0001-01-01 a 9999-12-31
Intervalo de tiempo 00:00:00 a 23:59:59.9999999 00:00:00 a 23:59:59.9999999
Longitud de caracteres 26 posiciones mínimo
34 máximo
19 posiciones mínimo
27 máximo
Tamaño de almacenamiento 8 a 10 bytes, dependiendo de la precisión*

* Más 1 byte para almacenar la precisión

6 a 8 bytes, dependiendo de la precisión*

* Más 1 byte para almacenar la precisión

Precisión 100 nanosegundos 100 nanosegundos
Precisión de fracciones de segundo
Precisión fraccionaria de segundo definida por el usuario
Rango de compensación de zona horaria -14:00 a +14:00 Ninguno
Reconocimiento y preservación de la compensación de zona horaria No
Consciente del horario de verano No No

¿Debería usar 'datetime2' o 'datetimeoffset'?

Esto depende de si necesita o no incluir una compensación de zona horaria.

Si necesita incluir una compensación de zona horaria, deberá usar datetimeoffset .

De lo contrario, utilice datetime2 , ya que ahorrará espacio de almacenamiento y eliminará cualquier posible problema de tener una compensación de zona horaria (potencialmente incorrecta) en sus datos.

Ejemplo 1:comparación básica

Aquí hay un ejemplo rápido para demostrar la diferencia básica entre datetime2 y desplazamiento de fecha y hora .

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

Resultado:

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

Aquí, configuro un datetime2 variable al mismo valor que el datetimeoffset variable. Esto hace que el valor se convierta a datetime2 y luego podemos usar un SELECT instrucción para ver el valor de cada variable.

Ambas variables usan una escala de 7, lo que significa que tienen 7 decimales.

Entonces, en este caso, la única diferencia entre los dos es que el datetimeoffset el valor incluye el desplazamiento de la zona horaria y el datetime2 el valor no.

Ejemplo 2:cambiar la precisión

Ambos tipos le permiten especificar una precisión (usando una escala entre 0 y 7). Por lo tanto, es posible configurar el datetime2 valor con una precisión menor que el datetimeoffset valor (y viceversa).

Ejemplo:

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

Resultado:

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

Aquí configuro el datetime2 valor a una escala de 3, lo que significa que termina con 3 lugares decimales en lugar de 7. En este caso, sus segundos fraccionarios se redondean hacia arriba (porque el siguiente dígito fraccionario es 5 o más).

Entonces podemos ver que es posible obtener un valor de fecha/hora diferente dependiendo de las fracciones de segundo que asignemos a datetime2 . Esto también funciona al revés (por ejemplo, si convertimos de datetime2(7) a datetimeoffset(3) ).

Sin embargo, si reducimos la parte fraccionaria, no se realiza el redondeo:

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

Resultado:

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

Ejemplo 3:configuración de valores a partir de literales de cadena

En los ejemplos anteriores, datetime2 el valor se asignó estableciéndolo en el mismo valor que el datetimeoffset valor. Cuando hacemos eso, SQL Server realiza una conversión implícita para que los datos "encajen" en el nuevo tipo de datos.

También podemos asignar el mismo valor directamente a datetime2 variable (aunque la documentación oficial no establece explícitamente que acepta un literal de cadena con un desplazamiento de zona horaria):

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

Resultado:

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

Ejemplo 4:tamaño de almacenamiento

La fechahora2 el tipo de datos usa dos bytes menos de almacenamiento que datetimeoffset para cualquier precisión dada.

La fechahora2 puede tener 6, 7 u 8 bytes, según su precisión.

El desplazamiento de fecha y hora puede tener 8, 9 o 10 bytes, según su precisión.

Microsoft afirma que datetime2 type también usa 1 byte adicional para almacenar su precisión, en cuyo caso usaría al menos 3 bytes más que smalldatetime .

Esto también se aplica a datetimeoffset (aunque no se indica explícitamente en la documentación de Microsoft).

Sin embargo, eso depende de si lo almacenamos en una tabla o en una variable, y si lo convertimos o no en una constante binaria.

Esto es lo que sucede si usamos DATALENGTH() función para devolver el número de bytes utilizados para cada uno de nuestros valores:

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

Resultado

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

Como era de esperar, 10 bytes para datetimeoffset y 8 bytes para datetime2 .

Pero si los convertimos a varbinary , obtenemos lo siguiente:

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

Resultado

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

Se agrega un byte adicional a cada valor para almacenar la precisión.

Muchos desarrolladores asumen que convertir a varbinary es representativo de cómo SQL Server realmente almacena los valores de fecha y hora. Sin embargo, esto es sólo parcialmente cierto.

Si bien es cierto que SQL Server almacena sus valores de fecha y hora en hexadecimal, ese valor hexadecimal en realidad no incluye la precisión. Esto se debe a que la precisión está incluida en la definición de la columna. Pero cuando convertimos a varbinary como hicimos en el ejemplo anterior, la precisión se antepone y esto agrega un byte adicional.

Para obtener más detalles sobre cómo se almacenan estos tipos de datos en diferentes contextos, consulte los siguientes artículos:

  • Comprender el tamaño de almacenamiento 'datetimeoffset' en SQL Server
  • Comprender el tamaño de almacenamiento 'datetime2' en SQL Server