En la documentación , se dice muy explícitamente que los únicos formatos seguros son los que mostré al comienzo de la pregunta:
yyyyMMdd -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff -- date dash separated, date/time separated by T
Sin embargo, recientemente me llamó la atención que hay un tercer formato que es igualmente inmune a cualquier configuración de idioma o formato de fecha:
yyyyMMdd hh:mm:ss.fff -- unseparated date, no T separator
TL; DR: Esto es cierto. Para datetime
y smalldatetime
.
Siga leyendo para obtener la versión más larga y la cantidad de pruebas que obtendrá.
Hay una laguna que explica esto: si bien el cuerpo del texto principal no reconoce yyyyMMdd hh:...
como un formato seguro del lenguaje transpuesto o las interpretaciones del formato de fecha, hay una pequeña propaganda que dice que la parte de fecha de una cadena de este tipo no se valida según la configuración del formato de fecha :
Es bastante diferente a mí tomar la documentación en su palabra, por lo general. Puedes decir que soy un poco escéptico. Y el lenguaje también es ambiguo aquí: solo indica que se trata de la combinación de fecha y hora, no de llamar explícitamente el espacio (eso podría ser un retorno de carro, por lo que sé). También dice que no es multilingüe, lo que significa que podría fallar en ciertos idiomas, pero pronto descubriremos que eso también es incorrecto.
Así que me propuse demostrar que ninguna combinación de lenguaje / formato de fecha podría hacer que este formato específico fallara.
Primero, creé un pequeño bloque de SQL dinámico para cada idioma:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
Esto produjo 34 filas de salida como esta:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
EXEC sys.sp_executesql @sql, N'@lang sysname', N'Deutsch';
EXEC sys.sp_executesql @sql, N'@lang sysname', N'Français';
EXEC sys.sp_executesql @sql, N'@lang sysname', N'日本語';
...
EXEC sys.sp_executesql @sql, N'@lang sysname', N'简体中文';
EXEC sys.sp_executesql @sql, N'@lang sysname', N'Arabic';
EXEC sys.sp_executesql @sql, N'@lang sysname', N'ไทย';
EXEC sys.sp_executesql @sql, N'@lang sysname', N'norsk (bokmål)';
Copié ese resultado en una nueva ventana de consulta y, sobre él, generé este código, que con suerte trataría de convertir esa misma fecha (el 13 de marzo) al tercer día del mes 13 en al menos un caso:
DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';
No, todos los idiomas trabajados solo se encuentran en ydm
. También probé todos los demás formatos, y también todos los tipos de datos de fecha / hora. 34 conversiones exitosas al 13 de marzo, cada vez.
Entonces, reconozco a @AndriyM y @ErikE que, de hecho, hay un tercer formato seguro. Lo tendré en cuenta para futuras publicaciones, pero he tocado la batería sobre los otros dos en tantos lugares, que no voy a cazarlos y corregirlos ahora.
Por extensión, pensarías que este sería seguro, pero no:
yyyyMMddThh:mm:ss.fff -- unseparated date, T separator
Creo que en todos los idiomas, esto producirá el equivalente de:
Msg 241, Nivel 16, Estado 1, La
conversión de la línea 8
falló al convertir la fecha y / o la hora de la cadena de caracteres.
Para completar, hay una cuarta formato seguro, pero sólo es seguro para las conversiones a los tipos de fecha / hora más nuevos ( date
, datetime2
, datetimeoffset
). En estos casos, la configuración del idioma no puede interferir:
yyyy-MM-dd hh:mm:...
Sin embargo, recomiendo encarecidamente su uso, ya que solo funciona para los tipos más nuevos, y los antiguos todavía tienen una gran cantidad de uso, en mi experiencia. ¿Por qué tener los guiones allí cuando en cualquier otro lugar (o de hecho en el mismo código, si el tipo de datos cambia) tiene que eliminarlos?
SET LANGUAGE Deutsch;
DECLARE @dashes char(10) = '2017-03-07 03:34';
DECLARE @d date = @dashes, @dt datetime = @dashes, @dt2 datetime2 = @dashes;
SELECT DATENAME(MONTH,@d), DATENAME(MONTH,@dt), DATENAME(MONTH,@dt2);
Incluso dada la misma cadena fuente, las conversiones arrojaron resultados bastante diferentes:
März Juli März
El formato que funciona para datetime ( yyyyMMdd
) también siempre funcionará para date y los otros tipos nuevos. Entonces, en mi humilde opinión, siempre usa eso. Y dado el tercer formato para los tipos con fecha / hora ( yyyyMMdd hh:...
), esto realmente le permitirá ser más consistente, incluso si el componente de fecha siempre es un poco menos legible.
Ahora solo me llevará unos años, más o menos, acostumbrarme a demostrar los tres formatos seguros cuando estoy hablando de la representación en cadena de fechas.