Uma coisa interessante sobre o
DATEDIFF()
função no SQL Server é que ele ignora seu SET DATEFIRST
valor. No entanto, isso não é um bug. Documentação da Microsoft para
DATEDIFF()
afirma claramente o seguinte:
EspecificandoSET DATEFIRST
não tem efeito emDATEDIFF
.DATEDIFF
sempre usa o domingo como o primeiro dia da semana para garantir que a função funcione de forma determinística.
Caso você não saiba,
SET DATEFIRST
define o primeiro dia da semana para sua sessão. É um número de 1 a 7 (que corresponde de segunda a domingo). O valor inicial para
SET DATEFIRST
édefinido implicitamente pela configuração do idioma (que poderádefinir com o SET LANGUAGE
demonstração). O valor real dependerá do idioma definido. Por exemplo, o valor padrão para o us_english
o idioma é 7
(Domingo), enquanto o padrão para o British
idioma é 1
(Segunda-feira). No entanto, você pode usar um
SET DATEFIRST
para substituir isso para que você possa continuar usando o mesmo idioma enquanto usa um dia diferente para o primeiro dia da semana. Mas como mencionado, o
SET DATEFIRST
valor não tem efeito no DATEDIFF()
função. O DATEDIFF()
função sempre assume que domingo é o primeiro dia da semana independentemente do seu SET DATEFIRST
valor. Isso pode causar alguns problemas interessantes ao usar
DATEDIFF()
se você não sabe como funciona. Se você se encontra nessa situação, espero que os exemplos nesta página possam ajudar.
Exemplo 1 – O problema
Primeiro, aqui está um exemplo do problema real. Observe que podemos recuperar o
SET DATEFIRST
valor selecionando @@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 Valor | us_english DATEDIFF() Resultado ||----------------------------------+------------------- -------------|| 7 | 0 |+-----------------------+----------------------- ---------++------------+--------------- --------------+| SET DATEFIRST Valor | Resultado britânico DATEDIFF() ||----------------------------------+------------------- ----------|| 1 | 0 |+-----------------------+----------------------- ------+
Nesse caso, a primeira data cai em um domingo e a segunda data em uma segunda-feira. Portanto, você normalmente esperaria que o
DATEDIFF()
britânico resultado para retornar 1
. Você esperaria isso porque o limite da parte da semana é cruzado quando vai de domingo a segunda (porque o SET DATEFIRST
o valor é 1
que significa “segunda-feira”, e segunda-feira marca o início de uma nova semana). Mas porque
DATEDIFF()
ignora seu SET DATEFIRST
valor e assume que domingo é o início da semana, obtemos o mesmo resultado para ambos os idiomas. Só para ter certeza, executarei a consulta novamente, mas desta vez definirei o
SET DATEFIRST
valor explicitamente . Em outras palavras, em vez de definir o idioma, usarei o SET DATEFIRST
demonstração: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 Valor | us_english DATEDIFF() Resultado ||----------------------------------+------------------- -------------|| 7 | 0 |+-----------------------+----------------------- ---------++------------+--------------- --------------+| SET DATEFIRST Valor | Resultado britânico DATEDIFF() ||----------------------------------+------------------- ----------|| 1 | 0 |+-----------------------+----------------------- ------+
Mesmo resultado, mesmo quando você define explicitamente o
SET DATEFIRST
valor. No entanto, isso não é surpresa – eu ficaria surpreso se não retornar o mesmo resultado. Além disso, isso simplesmente confirma que
DATEDIFF()
está funcionando exatamente como pretendido. Então, como podemos alterá-lo para que nosso
DATEDIFF()
os resultados honram nosso SET DATEFIRST
valor? A solução
Aqui está uma solução/solução que permitirá que você obtenha os resultados pretendidos. Isso garantirá que seu
SET DATEFIRST
configurações são fatoradas em seu DATEDIFF()
resultados. Tudo que você precisa fazer é subtrair
@@DATEFIRST
das datas 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 Valor', DATEADD(semana, DATEADD(dia, [email protected]@DATEFIRST, @datainicial), DATEADD(dia, [email protected]@DATEFIRST, @enddate)) AS 'Resultado britânico DATEDIFF()';
Resultado:
+-----------------------+---------------------- ----------+| SET DATEFIRST Valor | us_english DATEDIFF() Resultado ||----------------------------------+------------------- -------------|| 7 | 0 |+-----------------------+----------------------- ---------++------------+--------------- --------------+| SET DATEFIRST Valor | Resultado britânico DATEDIFF() ||----------------------------------+------------------- ----------|| 1 | 1 |+-----------------------+----------------------- ------+
Isso usa oDATEADD()
função para reduzir as datas de entrada pela quantidade de@@DATEFIRST
(que é o seuSET DATEFIRST
valor).
Neste caso, oDATEDIFF()
A função ainda usa domingo como o primeiro dia da semana, no entanto, as datas reais usadas no cálculo são diferentes. Eles foram movidos de volta no tempo pela quantidade de@@DATEFIRST
.
O exemplo a seguir mostra as datas que foram usadas no 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(dia, [email protected]@DATEFIRST, @startdate) AS 'Data Resultante'UNION ALLSELECT @enddate, @@DATEFIRST, DATEADD(dia, [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 ALLSELECT @enddate, @@DATEFIRST , DATEADD(dia, [email protected]@DATEFIRST, @enddate);
Resultado:
+-----------------+---------------+------------ ------+| Data Original | Subtrair por | Data resultante ||-----------------+---------------+---------------- ------|| 2025-01-05 | 7 | 29-12-2024 || 2025-01-06 | 7 | 30/12/2024 |+-----------------+---------------+--------- ---------++------+---------------+----- -------------+| Data Original | Subtrair por | Data resultante ||-----------------+---------------+---------------- ------|| 2025-01-05 | 1 | 04-01-2025 || 2025-01-06 | 1 | 2025-01-05 |+-----------------+---------------+--------- ---------+
Portanto, em nossa solução alternativa,DATEDIFF()
utilizou a “Data Resultante” em seus cálculos.
Se você está tendo problemas comDATEDIFF()
ignorandoSET DATEFIRST
, espero que este artigo tenha ajudado.