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 DATEFIRSTnão tem efeito emDATEDIFF.DATEDIFFsempre 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 , example@sqldat.com@DATEFIRST, @startdate), DATEADD(day, example@sqldat.com@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Result';SET DATEFIRST 1;SELECT @@DATEFIRST AS 'SET DATEFIRST Valor', DATEADD(semana, DATEADD(dia, exemplo@sqldat.com@DATEFIRST, @datainicial), DATEADD(dia, exemplo@sqldat.com@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 DATEFIRSTvalor).
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, exemplo@sqldat.com@DATEFIRST, @startdate) AS 'Data Resultante'UNION ALLSELECT @enddate, @@DATEFIRST, DATEADD(dia, exemplo@sqldat.com@DATEFIRST, @enddate); SET DATEFIRST 1;SELECT @startdate AS 'Original Date', @@DATEFIRST AS 'Subtract By', DATEADD(day, example@sqldat.com@DATEFIRST, @startdate) AS 'Resulting Date'UNION ALLSELECT @enddate, @@DATEFIRST , DATEADD(dia, exemplo@sqldat.com@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.