Resumen: En cada país, en cada idioma, en cada región... usamos un formato diferente para representar las fechas. SQL Server permite comparar columnas que almacenan fechas contra cadenas de textos que convierte internamente al tipo de datos necesario. Sin embargo, según la configuración regional del servidor, la misma cadena puede ser interpretada de diferentes formas, generando errores que incluso pueden pasar inadvertidos. Para solucionarlo existe un formato de fecha estándar e independiente de cualquier configuración que hay que usar siempre: 'yyyymmdd'.
Así pues, como se puede observar en este extenso artículo de la Wikipedia, el mismo dato se puede representar de múltiples formas; una misma fecha puede representarse con distintas ordenaciones de sus componentes y con distintos separadores entre ellos.
Por ello, es inevitable que cuando queramos poner una fecha en una consulta para compararla contra un campo de tipo date, datetime o datetime2 nos preguntemos: "¿en qué formato la pongo?"
Supongamos que tenemos una base de datos de compras en nuestro entorno de desarrollo con la que trabajamos en español y queremos obtener todos los pedidos hechos el 12 de febrero de 2014.
La consulta que realizaríamos sería la siguiente:
Esta consulta funcionaría correctamente siempre y cuando la ejecutásemos solamente en servidores configurados en español. Sin embargo, si la ejecutásemos contra un servidor configurado en inglés, ¡estaríamos pidiendo de repente los pedidos generados el 2 de diciembre de 2014!
Tendríamos, pues, un error que pasaría inadvertido hasta que un usuario se diese cuenta de que no está obteniendo los resultados que esperaba. Esto puede tener consecuencias bastante desastrosas para consultas que afecten a fechas de caducidad, contabilidad, programas de fidelización de clientes... ¡cualquier cosa!
Puedes hacer la siguiente prueba para comprender mejor lo que está ocurriendo (además de SET LANGUAGE, existe el comando SET DATEFORMAT, que también puede cambiar la forma de SQL Server de interpretar una fecha):
Verás que el resultado cambia. En inglés se nos devuelve el mes December (diciembre), mientras que en español el mes resultante es mayo. Si la fecha consultada hubiese sido del día 13 en adelante de cualquier mes, se habría producido directamente un error ejecutando la consulta contra cualquier servidor configurado en inglés o cualquier otro idioma que espere un formato del tipo mm/dd/yyyy.
Se puede comprobar, imitando el script de prueba anterior, que a SQL Server no le afecta en absoluto la configuración actual de idioma:
Esta vez hemos obtenido el mismo resultado tanto para inglés como para español: Febrero.
Otros formatos posibles son:
También existe un formato universal con separador de fechas, que siempre ha de llevar hora (solamente los milisegundos son opcionales), y que es el siguiente: 'yyyy-mm-ddThh:mm:ss.[mmm]'.
Referencias:
El problema
Todos sabemos que las fechas no se representan igual en todas las partes del mundo. Mientras que en España, por ejemplo, es típico usar el formato dd/mm/yyyy, donde d es día, m es año y la y representa al año (la fecha de publicación de este artículo en dicho formato sería 20/02/2014), en Alemania se usaría dd.mm.yyyy, pero en Estados Unidos sería mm/dd/yyyy.Así pues, como se puede observar en este extenso artículo de la Wikipedia, el mismo dato se puede representar de múltiples formas; una misma fecha puede representarse con distintas ordenaciones de sus componentes y con distintos separadores entre ellos.
Por ello, es inevitable que cuando queramos poner una fecha en una consulta para compararla contra un campo de tipo date, datetime o datetime2 nos preguntemos: "¿en qué formato la pongo?"
La importancia del formato
El mismo formato puede funcionar, no funcionar o devolver resultados incorrectos, según lo que espere el servidor contra el que trabajemos. No es una cuestión trivial, ya que equivocarse en el formato puede producir resultados inesperados en el peor momento.Supongamos que tenemos una base de datos de compras en nuestro entorno de desarrollo con la que trabajamos en español y queremos obtener todos los pedidos hechos el 12 de febrero de 2014.
La consulta que realizaríamos sería la siguiente:
Esta consulta funcionaría correctamente siempre y cuando la ejecutásemos solamente en servidores configurados en español. Sin embargo, si la ejecutásemos contra un servidor configurado en inglés, ¡estaríamos pidiendo de repente los pedidos generados el 2 de diciembre de 2014!
Tendríamos, pues, un error que pasaría inadvertido hasta que un usuario se diese cuenta de que no está obteniendo los resultados que esperaba. Esto puede tener consecuencias bastante desastrosas para consultas que afecten a fechas de caducidad, contabilidad, programas de fidelización de clientes... ¡cualquier cosa!
Puedes hacer la siguiente prueba para comprender mejor lo que está ocurriendo (además de SET LANGUAGE, existe el comando SET DATEFORMAT, que también puede cambiar la forma de SQL Server de interpretar una fecha):
Verás que el resultado cambia. En inglés se nos devuelve el mes December (diciembre), mientras que en español el mes resultante es mayo. Si la fecha consultada hubiese sido del día 13 en adelante de cualquier mes, se habría producido directamente un error ejecutando la consulta contra cualquier servidor configurado en inglés o cualquier otro idioma que espere un formato del tipo mm/dd/yyyy.
El formato independiente, al rescate
Para solucionar estos problemas existe un formato universal, que SQL Server entiende siempre, y que es totalmente independiente de cualquier configuración del servidor.
Cualquier fecha representada de la siguiente manera es interpretada siempre correctamente:
'yyyymmdd'
Así pues, en nuestro ejemplo anterior, para pedir los pedidos del día 12 de febrero de 2014, utilizaríamos la siguiente consulta:
Se puede comprobar, imitando el script de prueba anterior, que a SQL Server no le afecta en absoluto la configuración actual de idioma:
Esta vez hemos obtenido el mismo resultado tanto para inglés como para español: Febrero.
Otros formatos posibles son:
- Para fechas cortas: 'yymmdd'
- Para fechas con hora incluida: 'yyyymmdd hh:mm:ss.mmm'
También existe un formato universal con separador de fechas, que siempre ha de llevar hora (solamente los milisegundos son opcionales), y que es el siguiente: 'yyyy-mm-ddThh:mm:ss.[mmm]'.
Referencias:
- Inside Microsoft SQL Server 2005: T-SQL Programming, by Itzik Ben-Gan
- Aaron Bertrand's "Bad habits to kick: mis-handling date / range queries"
Excelente información, muy claro, me sirvio mucho para los que estamos empezando en todo esto.
ResponderEliminarGracias
Gracias a ti por el comentario, Ignacio.
EliminarChamo, me has salvado!!, excelente aporte!!.
ResponderEliminarMe alegro.
EliminarSaludos.