Na documentação , é afirmado explicitamente que os únicos formatos seguros são os que demonstrei no início da pergunta:
yyyyMMdd -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff -- date dash separated, date/time separated by T
No entanto, recentemente, soube que existe um terceiro formato igualmente imune a qualquer configuração de idioma ou formato de data:
yyyyMMdd hh:mm:ss.fff -- unseparated date, no T separator
TL; DR: Isso é verdade. Para datetime
e smalldatetime
.
Continue lendo para a versão mais longa e com todas as provas que conseguir.
Existe uma brecha que explica isso - embora o corpo do texto principal não reconheça yyyyMMdd hh:...
como um formato protegido de interpretações de idiomas ou formatos de data transpostos, há um pequeno resumo que diz que a parte da data de uma string não é validada, dependendo das configurações do formato da data:
É bastante diferente de mim apenas pegar a documentação em sua palavra, normalmente. Você pode dizer que sou um pouco cético. E a linguagem também é ambígua aqui - apenas afirma que se trata da combinação de data e hora, não chamando o espaço explicitamente (isso poderia ser um retorno de carro, pelo que sei). Ele também diz que não é multilíngue, o que significa que pode falhar em alguns idiomas, mas descobriremos em breve que isso também está incorreto.
Então, decidi provar que nenhuma combinação de idioma / formato de data poderia fazer esse formato específico falhar.
Primeiro, criei um pequeno bloco de SQL dinâmico para cada idioma:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
Isso produziu 34 linhas de saída 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)';
Copiei essa saída para uma nova janela de consulta e, acima dela, gerei esse código, que esperançosamente tentaria converter a mesma data (13 de março) para o 3º dia do 13º mês em pelo menos um caso:
DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';
Não, todas as línguas trabalhadas são encontradas ydm
. Também tentei todos os outros formatos e também todos os tipos de dados de data / hora. 34 conversões bem-sucedidas para 13 de março, todas as vezes.
Portanto, concordo com @AndriyM e @ErikE que, de fato, existe um terceiro formato seguro. Vou manter isso em mente para posts futuros, mas já toquei a bateria dos outros dois em tantos lugares que não vou caçar todos e corrigi-los agora.
Por extensão, você pensaria que este seria seguro, mas não:
yyyyMMddThh:mm:ss.fff -- unseparated date, T separator
Eu acho que em todas as línguas, isso renderá o equivalente a:
Mensagem 241, nível 16, estado 1, linha 8
Falha na conversão ao converter data e / ou hora da cadeia de caracteres.
Para completar, há uma quarta formato seguro, mas só é seguro para as conversões para os tipos de data / hora mais recentes ( date
, datetime2
, datetimeoffset
). Nesses casos, as configurações de idioma não podem interferir:
yyyy-MM-dd hh:mm:...
No entanto, eu recomendo contra o seu uso, porque ele funciona apenas para os tipos mais recentes, e os antigos ainda estão em uso massivo, na minha experiência. Por que os traços estão lá quando em qualquer outro lugar (ou de fato nesse mesmo código, se o tipo de dados mudar) você precisa removê-los?
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);
Mesmo com a mesma sequência de origem, as conversões renderam resultados bastante diferentes:
März Juli März
O formato que funciona para datetime ( yyyyMMdd
) também sempre funcionará para data e outros tipos novos. Então, IMHO, sempre use isso. E dado o terceiro formato para tipos com data / hora ( yyyyMMdd hh:...
), isso permitirá que você seja mais consistente - mesmo que o componente de data seja sempre um pouco menos legível.
Agora, levarei apenas alguns anos, mais ou menos, para adquirir o hábito de demonstrar os três formatos seguros quando estou falando sobre a representação de datas das strings.