W dokumentacji wyraźnie zaznaczono, że jedynymi bezpiecznymi formatami są te, które zademonstrowałem na samym początku pytania:
yyyyMMdd -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff -- date dash separated, date/time separated by T
Jednak niedawno zwrócono mi uwagę, że istnieje trzeci format, który jest równie odporny na wszelkie ustawienia języka lub formatu daty:
yyyyMMdd hh:mm:ss.fff -- unseparated date, no T separator
TL; DR: To prawda. Dla datetime
i smalldatetime
.
Czytaj dalej, aby uzyskać dłuższą wersję i tyle dowodów, ile dostaniesz.
Istnieje luka, która to wyjaśnia - podczas gdy główna treść tekstu nie uznaje się yyyyMMdd hh:...
za format bezpieczny przed transponowanym językiem lub interpretacjami formatu daty, istnieje mały napis, który mówi, że część daty takiego ciągu nie jest sprawdzana w zależności od ustawień formatu daty :
Zwykle raczej nie podoba mi się tylko przyjmowanie dokumentacji za słowo. Możesz powiedzieć, że jestem trochę sceptyczny. Język też jest tu niejednoznaczny - stwierdza tylko, że chodzi o połączenie daty i godziny, a nie wyraźne wzywanie miejsca (to wszystko, co wiem, może być znakiem powrotu karetki). Mówi także, że nie jest on wielojęzyczny, co oznacza, że może zawieść w niektórych językach, ale wkrótce dowiemy się, że to również jest niepoprawne.
Dlatego postanowiłem udowodnić, że żadna kombinacja języka / formatu daty nie może spowodować niepowodzenia tego konkretnego formatu.
Najpierw stworzyłem mały blok dynamicznego SQL dla każdego języka:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
To dało 34 wiersze wyników takich jak to:
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)';
Skopiowałem ten wynik do nowego okna zapytania, a nad nim wygenerowałem ten kod, który, mam nadzieję, spróbuje przekonwertować tę samą datę (13 marca) na trzeci dzień 13 miesiąca w co najmniej jednym przypadku:
DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';
Nie, każdy język, w którym tylko się znalazło, działał ydm
. Próbowałem też każdego innego formatu, a także każdego typu danych data / czas. 34 udane konwersje do 13 marca za każdym razem.
Przyznaję więc @AndriyM i @ErikE, że rzeczywiście istnieje trzeci bezpieczny format. Będę o tym pamiętać w przyszłych postach, ale waliłem w bębny o pozostałe dwa w tak wielu miejscach, że nie zamierzam ich teraz wyłapywać i poprawiać.
Zasadniczo wydaje ci się, że ten będzie bezpieczny, ale nie:
yyyyMMddThh:mm:ss.fff -- unseparated date, T separator
Myślę, że w każdym języku da to równowartość:
Wiadomość 241, poziom 16, stan 1, wiersz 8
Konwersja nie powiodła się podczas konwersji daty i / lub godziny z ciągu znaków.
Dla kompletności, jest czwartą bezpieczny formatu, ale jest bezpieczny tylko dla konwersji do nowszych typów data / czas ( date
, datetime2
, datetimeoffset
). W takich przypadkach ustawienia języka nie mogą zakłócać:
yyyy-MM-dd hh:mm:...
Jednak zdecydowanie odradzam jego użycie, ponieważ działa tylko dla nowszych typów, a stare są nadal bardzo intensywne , z mojego doświadczenia. Dlaczego myślniki są tam, skoro wszędzie indziej (lub w rzeczywistości w tym samym kodzie, jeśli zmienia się typ danych), trzeba je usunąć?
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);
Nawet biorąc pod uwagę ten sam ciąg źródłowy, konwersje dały całkiem inne wyniki:
März Juli März
Format, który działa na datetime ( yyyyMMdd
) będzie również zawsze aktualne i praca dla innych nowych typów. IMHO, po prostu zawsze tego używaj. Biorąc pod uwagę trzeci format typów z datą / godziną ( yyyyMMdd hh:...
), pozwoli to zachować większą spójność - nawet jeśli składnik daty jest zawsze nieco mniej czytelny.
Teraz zajmie mi tylko kilka lat, daję lub biorę, aby przyzwyczaić się do demonstrowania trzech bezpiecznych formatów, kiedy mówię o ciągach reprezentujących daty.