В документации очень четко указано, что единственными безопасными форматами являются те, которые я продемонстрировал в самом начале вопроса:
yyyyMMdd -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff -- date dash separated, date/time separated by T
Однако недавно мне стало известно, что существует третий формат, который одинаково невосприимчив к любым настройкам языка или формата даты:
yyyyMMdd hh:mm:ss.fff -- unseparated date, no T separator
TL; DR: это правда. Для datetime
и smalldatetime
.
Продолжайте читать для более длинной версии, и примерно столько доказательств, сколько вы собираетесь получить.
Существует лазейка, которая объясняет это - хотя основное тело текста не может быть признано yyyyMMdd hh:...
форматом, безопасным для транспонированных языков или интерпретаций формата даты, есть небольшая реклама, которая говорит, что часть даты в такой строке не проверена в зависимости от настроек dateformat:
Обычно я совсем не согласен с документацией. Вы можете сказать, что я немного скептически. И язык здесь тоже неоднозначен - он просто говорит о том, что речь идет о комбинации даты и времени, а не о явном вызове пробела (насколько я знаю, это может быть возврат каретки). В нем также говорится, что это не мультиязычный язык, что означает, что он может не работать на определенных языках, но вскоре мы выясним, что это также неверно.
Поэтому я решил доказать, что ни одна комбинация языка / даты не сможет сделать этот конкретный формат неудачным.
Сначала я создал небольшой блок динамического SQL для каждого языка:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
Это произвело 34 ряда вывода как это:
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)';
Я скопировал этот вывод в новое окно запроса и над ним сгенерировал этот код, который, мы надеемся, попытается преобразовать эту же дату (13 марта) в 3-й день 13-го месяца хотя бы в одном случае:
DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';
Нет, каждый язык работал просто найти в ydm
. Я попробовал любой другой формат, а также каждый тип данных даты / времени. 34 успешных преобразования в 13 марта, каждый раз.
Итак, я согласен с @AndriyM и @ErikE, что действительно существует третий безопасный формат. Я буду помнить это для будущих постов, но я разбил барабаны о двух других во многих местах, я не собираюсь выслеживать их все и исправлять их сейчас.
По сути, вы думаете, что это будет безопасно, но нет:
yyyyMMddThh:mm:ss.fff -- unseparated date, T separator
Я думаю, что на каждом языке это даст эквивалент:
Сообщение 241, Уровень 16, Состояние 1, Строка 8
Преобразование не выполнено при преобразовании даты и / или времени из символьной строки.
Для полноты картины , есть четвертый безопасный формат, но это безопасно только для преобразования в более новых типов даты / времени ( date
, datetime2
, datetimeoffset
). В этих случаях языковые настройки не могут мешать:
yyyy-MM-dd hh:mm:...
Тем не менее, я настоятельно рекомендую против его использования, потому что он работает только для новых типов, а старые, по моему опыту, все еще широко используются. Зачем черточки там, когда везде (или на самом деле в том же коде, если тип данных меняется) вы должны их удалить?
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);
Даже при одной и той же исходной строке преобразования дали совершенно разные результаты:
März Juli März
Формат, который работает для datetime ( yyyyMMdd
), также всегда будет работать для даты и других новых типов. Так что, имхо, просто всегда этим пользуюсь. А учитывая третий формат для типов с date / time ( yyyyMMdd hh:...
), это фактически позволит вам быть более последовательным, даже если компонент даты всегда немного менее читабелен.
Теперь у меня уйдет несколько лет, чтобы дать или взять привычку демонстрировать три безопасных формата, когда я говорю о строковом представлении дат.