Buscar este blog

jueves, 20 de febrero de 2014

Formato de fechas en SQL Server

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'.


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'
Estos tres formatos se resumen en el patrón '[yy]yymmdd [hh:mm[:ss][.mmm]]' donde todo lo que está entre corchetes es opcional.

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:

No hay comentarios:

Publicar un comentario