Trong tài liệu , có tuyên bố rất rõ ràng rằng các định dạng an toàn duy nhất là những định dạng tôi đã trình bày ở phần đầu của câu hỏi:
yyyyMMdd -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff -- date dash separated, date/time separated by T
Tuy nhiên, gần đây tôi đã nhận thấy rằng có một định dạng thứ ba miễn nhiễm như nhau đối với bất kỳ cài đặt ngôn ngữ hoặc định dạng ngày nào:
yyyyMMdd hh:mm:ss.fff -- unseparated date, no T separator
TL; DR: Đây là sự thật.Cho datetime
và smalldatetime
.
Đọc tiếp cho phiên bản dài hơn và về nhiều bằng chứng bạn sẽ nhận được.
Có một lỗ hổng giải thích điều này - trong khi phần thân văn bản chính không thừa nhận yyyyMMdd hh:...
là một định dạng an toàn khỏi các diễn giải định dạng ngôn ngữ hoặc ngày chuyển đổi, có một chút lúng túng nói rằng phần ngày của chuỗi đó không được xác thực tùy thuộc vào cài đặt định dạng ngày:
Nó thường không giống như tôi chỉ lấy tài liệu theo từ của nó, thường. Bạn có thể nói tôi hơi hoài nghi. Và ngôn ngữ cũng mơ hồ ở đây - nó chỉ nói rằng đây là sự kết hợp giữa ngày và thời gian, không gọi ra không gian một cách rõ ràng (đó có thể là sự trở lại của xe ngựa, đối với tất cả những gì tôi biết). Nó cũng nói rằng nó không phải là đa ngôn ngữ, điều đó có nghĩa là nó có thể bị lỗi ở một số ngôn ngữ nhất định, nhưng chúng tôi sẽ sớm phát hiện ra rằng điều đó cũng không chính xác.
Vì vậy, tôi đặt ra để chứng minh rằng không có sự kết hợp nào giữa ngôn ngữ / dateformat có thể làm cho định dạng cụ thể này thất bại.
Đầu tiên, tôi tạo một khối SQL động nhỏ cho mỗi ngôn ngữ:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
Điều này tạo ra 34 hàng đầu ra như thế này:
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)';
Tôi đã sao chép đầu ra đó sang một cửa sổ truy vấn mới và trên nó, tôi đã tạo mã này, hy vọng sẽ cố gắng chuyển đổi cùng ngày đó (ngày 13 tháng 3) sang ngày thứ 3 của tháng thứ 13 trong ít nhất một trường hợp:
DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';
Không, mọi ngôn ngữ làm việc chỉ cần tìm trong ydm
. Tôi cũng đã thử mọi định dạng khác và cả kiểu dữ liệu ngày / giờ. 34 chuyển đổi thành công đến ngày 13 tháng 3, mọi lúc.
Vì vậy, tôi thừa nhận với @AndriyM và @ErikE rằng, thực sự, có một định dạng an toàn thứ 3. Tôi sẽ ghi nhớ điều này cho các bài viết trong tương lai, nhưng tôi đã đánh trống cho hai người kia ở rất nhiều nơi, tôi sẽ không săn lùng tất cả và sửa chúng ngay bây giờ.
Về phần mở rộng, bạn sẽ nghĩ cái này sẽ an toàn, nhưng không:
yyyyMMddThh:mm:ss.fff -- unseparated date, T separator
Tôi nghĩ trong mọi ngôn ngữ, điều này sẽ mang lại tương đương với:
Msg 241, Cấp 16, Trạng thái 1,
Chuyển đổi Dòng 8
không thành công khi chuyển đổi ngày và / hoặc thời gian từ chuỗi ký tự.
Để hoàn chỉnh, có một định dạng an toàn thứ tư, nhưng nó chỉ là an toàn cho các chuyển đổi cho các loại ngày / giờ mới hơn ( date
, datetime2
, datetimeoffset
). Trong những trường hợp này, cài đặt ngôn ngữ không thể can thiệp:
yyyy-MM-dd hh:mm:...
Tuy nhiên, tôi đánh giá cao việc sử dụng nó vì nó chỉ hoạt động cho các loại mới hơn và những loại cũ vẫn còn sử dụng rất nhiều, theo kinh nghiệm của tôi. Tại sao có dấu gạch ngang ở đó khi mọi nơi khác (hoặc trên thực tế trong cùng một mã, nếu kiểu dữ liệu thay đổi) bạn phải xóa chúng?
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);
Ngay cả với cùng một chuỗi nguồn, các chuyển đổi mang lại kết quả khá khác nhau:
März Juli März
Định dạng hoạt động cho datetime ( yyyyMMdd
) cũng sẽ luôn hoạt động cho ngày và các loại mới khác. Vì vậy, IMHO, chỉ luôn luôn sử dụng đó. Và được đưa ra định dạng thứ ba cho các loại có ngày / giờ ( yyyyMMdd hh:...
), điều này thực sự sẽ cho phép bạn nhất quán hơn - ngay cả khi thành phần ngày luôn dễ đọc hơn một chút.
Bây giờ tôi sẽ chỉ mất vài năm, cho hoặc nhận, để có thói quen thể hiện ba định dạng an toàn khi tôi nói về biểu diễn chuỗi ngày.