Algo interesante sobre el DATEDIFF()
función en SQL Server es que ignora su SET DATEFIRST
valor.
Sin embargo, esto no es un error. Documentación de Microsoft para DATEDIFF()
establece claramente lo siguiente:
Especificando SET DATEFIRST
no tiene efecto en DATEDIFF
. DATEDIFF
siempre usa el domingo como el primer día de la semana para garantizar que la función opere de manera determinista.
En caso de que no lo sepas, SET DATEFIRST
establece el primer día de la semana para su sesión. Es un número del 1 al 7 (que corresponde de lunes a domingo).
El valor inicial para SET DATEFIRST
está establecido implícitamente por la configuración de idioma (que puede establecer con SET LANGUAGE
declaración). El valor real dependerá del idioma que se establezca. Por ejemplo, el valor predeterminado para us_english
el idioma es 7
(domingo), mientras que el valor predeterminado para el British
el idioma es 1
(Lunes).
Sin embargo, puede usar un SET DATEFIRST
declaración para anular esto para que pueda seguir usando el mismo idioma mientras usa un día diferente para el primer día de la semana.
Pero como se mencionó, el SET DATEFIRST
el valor no tiene efecto en el DATEDIFF()
función. El DATEDIFF()
La función siempre asume que el domingo es el primer día de la semana, independientemente de su SET DATEFIRST
valor.
Esto puede causar algunos problemas interesantes al usar DATEDIFF()
si no sabes cómo funciona.
Si te encuentras en esta situación, esperamos que los ejemplos de esta página puedan ayudarte.
Ejemplo 1:el problema
Primero, aquí hay un ejemplo del problema real. Tenga en cuenta que podemos recuperar el SET DATEFIRST
valor seleccionando @@DATEFIRST
.
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET LANGUAGE us_english; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'us_english DATEDIFF() Result'; SET LANGUAGE British; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';
Resultado:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 0 | +-----------------------+-----------------------------+
En este caso, la primera fecha cae en domingo y la segunda fecha en lunes. Por lo tanto, normalmente esperaría que el británico DATEDIFF()
resultado para devolver 1
. Esperaría esto porque el límite de la parte de la semana se cruza cuando va de domingo a lunes (porque SET DATEFIRST
el valor es 1
que significa “lunes”, y el lunes marca el comienzo de una nueva semana).
Pero debido a que DATEDIFF()
ignora su SET DATEFIRST
valor y asume que el domingo es el comienzo de la semana, obtenemos el mismo resultado para ambos idiomas.
Solo para estar seguro, volveré a ejecutar la consulta, pero esta vez configuraré SET DATEFIRST
valor explícitamente . En otras palabras, en lugar de configurar el idioma, usaré SET DATEFIRST
declaración:
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET DATEFIRST 7; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'us_english DATEDIFF() Result'; SET DATEFIRST 1; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';
Resultado:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 0 | +-----------------------+-----------------------------+
Mismo resultado, incluso cuando configura explícitamente SET DATEFIRST
valor. Sin embargo, esto no es una sorpresa; me sorprendería si no devolver el mismo resultado.
Además, esto simplemente confirma que DATEDIFF()
está funcionando exactamente como se esperaba.
Entonces, ¿cómo lo cambiamos para que nuestro DATEDIFF()
los resultados respetan nuestro SET DATEFIRST
valor?
La solución
Aquí hay una solución que le permitirá obtener los resultados deseados. Esto asegurará que su SET DATEFIRST
la configuración se tiene en cuenta en su DATEDIFF()
resultados.
Todo lo que necesitas hacer es restar @@DATEFIRST
a partir de las fechas de entrada.
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET DATEFIRST 7; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, DATEADD(day, [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Result'; SET DATEFIRST 1; SELECT @@DATEFIRST AS 'SET DATEFIRST Value', DATEDIFF(week, DATEADD(day, [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'British DATEDIFF() Result';
Resultado:
+-----------------------+--------------------------------+ | SET DATEFIRST Value | us_english DATEDIFF() Result | |-----------------------+--------------------------------| | 7 | 0 | +-----------------------+--------------------------------+ +-----------------------+-----------------------------+ | SET DATEFIRST Value | British DATEDIFF() Result | |-----------------------+-----------------------------| | 1 | 1 | +-----------------------+-----------------------------+
Esto usa el DATEADD()
función para reducir las fechas de entrada por la cantidad de @@DATEFIRST
(que es su SET DATEFIRST
valor).
En este caso el DATEDIFF()
La función todavía usa el domingo como el primer día de la semana, sin embargo, las fechas reales usadas en el cálculo son diferentes. Han retrocedido en el tiempo por la cantidad de @@DATEFIRST
.
El siguiente ejemplo muestra las fechas que se usaron en el cálculo:
DECLARE @startdate date = '2025-01-05', @enddate date = '2025-01-06'; SET DATEFIRST 7; SELECT @startdate AS 'Original Date', @@DATEFIRST AS 'Subtract By', DATEADD(day, [email protected]@DATEFIRST, @startdate) AS 'Resulting Date' UNION ALL SELECT @enddate, @@DATEFIRST, DATEADD(day, [email protected]@DATEFIRST, @enddate); SET DATEFIRST 1; SELECT @startdate AS 'Original Date', @@DATEFIRST AS 'Subtract By', DATEADD(day, [email protected]@DATEFIRST, @startdate) AS 'Resulting Date' UNION ALL SELECT @enddate, @@DATEFIRST, DATEADD(day, [email protected]@DATEFIRST, @enddate);
Resultado:
+-----------------+---------------+------------------+ | Original Date | Subtract By | Resulting Date | |-----------------+---------------+------------------| | 2025-01-05 | 7 | 2024-12-29 | | 2025-01-06 | 7 | 2024-12-30 | +-----------------+---------------+------------------+ +-----------------+---------------+------------------+ | Original Date | Subtract By | Resulting Date | |-----------------+---------------+------------------| | 2025-01-05 | 1 | 2025-01-04 | | 2025-01-06 | 1 | 2025-01-05 | +-----------------+---------------+------------------+
Entonces, en nuestra solución alternativa, DATEDIFF()
usó la "Fecha resultante" en sus cálculos.
Si ha tenido problemas con DATEDIFF()
ignorando SET DATEFIRST
, espero que este artículo haya ayudado.