Vamos por partes.
La representación interna de SQL Server es independiente de la representación visual de la fecha. Es decir un valor DATETIME usa 8 bytes: 4 para la fecha, cuatro para la hora y un SMALLDATETIME usa 4: 2 para la fecha y dos para la hora. El formato debe importar solamente al momento de mostrar el resultado de una consulta.
Por otra parte el error debe estar en la manera en que las usas en el código. Pero es muy fácil aclararlo.
Con cada sesión que abras al motor, se te asigna un idioma por defecto. Y este idioma determina la opción DATEFORMAT que se te asigna. Ahora bien este formato no determina como se va a mostrar la fecha, sino cómo deben interpretarse las cadenas que contengan un literal de fecha. Puesto que la opción DATEFORMAT puede cambiar entre servidores, e incluso en un mismo servidor puede ser distinta entre logins, hay que usar para las literales un formato que no dé lugar a ambiguedades. Dichos formatos son el ISO y el ISO8601.
Hagamos unas pruebas. En el sistema en que estoy el idioma es Inglés, y la opción DATEFORMAT es mdy. Puedes averiguar tu opción actual con
Probemos lo siguiente:
Código:
--Formatos inseguros
select cast('02/01/2008' as datetime) --MM/DD/YYY
select cast('2008/02/01' as datetime) --YYYY/MM/DD
select cast('2008.02.01' as datetime) --YYYY.MM.DD (ANSI)
select cast('2008-02-01' as datetime) --YYYY-MM-DD
--Formatos seguros
select cast('20080201' as datetime) --ISO
select cast('2008-02-01T00:00:00' as datetime) --ISO8601
Puesto que meses y días en los formatos 'inseguros' coinciden en orden con la opcion DATEFORMAT (mdy), no ha ocurrido ningún problema.
Ahora, probemos que pasaría con una opción DATEFORMAT distinta. Por ejemplo la que habría si el idioma fuera el español:
Código:
set dateformat dmy
--Formatos inseguros
select cast('02/01/2008' as datetime) --MM/DD/YYY
select cast('2008/02/01' as datetime) --YYYY/MM/DD
select cast('2008.02.01' as datetime) --YYYY.MM.DD (ANSI)
select cast('2008-02-01' as datetime) --YYYY-MM-DD
--Formatos seguros
select cast('20080201' as datetime) --ISO
select cast('2008-02-01T00:00:00' as datetime) --ISO8601
Los resultados hablan por si mismos. Como puedes ver, hay posibilidad de errores cuando en el código usamos asignaciones o comparaciones que pueden ser ambiguas. Mi código puede funcionar muy bien ahora en mi sistema en Inglés, pero ¿y si alguien replica este código a un sistema en francés o español?
Si vas a comparar o asignar a un campo fecha lo mejor evidentemente es hacerlo con una fecha. Pero si debes usar un literal, asegúrate de que esté en formato iso. Si este literal viniera por ejemplo de una aplicación que llama a un procedimiento y no hubiera posibilidad de corregirle el formato desde la aplicación, debes averiguar exactamente que representan cada una de las partes en el literal para que puedas convertirlo adecuadamente. En el último de los casos, usar
set dateformat con el formato deseado.
Cuando hice las pruebas con los formatos, encontré con horror que anteriormente recomendé el formato 'YYYY-MM-DD' como seguro, cuando realmente no lo es. Sucede que sin pensarlo más lo escribí omitiendo la parte del tiempo. Mil disculpas.