Dalam dokumentasi , secara eksplisit dinyatakan bahwa satu-satunya format aman adalah yang saya contohkan di awal pertanyaan:
yyyyMMdd -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff -- date dash separated, date/time separated by T
Namun, baru-baru ini menarik perhatian saya bahwa ada format ketiga yang sama-sama kebal terhadap pengaturan bahasa atau format tanggal:
yyyyMMdd hh:mm:ss.fff -- unseparated date, no T separator
TL; DR: Ini benar. Untuk datetime
dan smalldatetime
.
Baca terus untuk versi yang lebih panjang, dan tentang sebanyak mungkin bukti yang akan Anda dapatkan.
Ada celah yang menjelaskan hal ini - sementara badan teks utama gagal untuk mengakui yyyyMMdd hh:...
sebagai format aman dari terjemahan bahasa atau interpretasi format tanggal, ada uraian kecil yang mengatakan bagian tanggal dari string semacam itu tidak divalidasi tergantung pada pengaturan format tanggal :
Ini agak tidak seperti saya untuk hanya mengambil dokumentasi sesuai kata-katanya, biasanya. Bisa dibilang saya agak skeptis. Dan bahasanya di sini juga ambigu - hanya menyatakan bahwa ini adalah tentang kombinasi tanggal dan waktu, tidak menyebut ruang secara eksplisit (yang bisa menjadi carriage return, untuk semua yang saya tahu). Ia juga mengatakan bahwa itu bukan multi-bahasa, yang berarti bisa gagal dalam bahasa tertentu, tetapi kami akan segera mengetahui bahwa itu juga salah.
Jadi saya berangkat untuk membuktikan bahwa tidak ada kombinasi bahasa / format tanggal yang dapat membuat format spesifik ini gagal.
Pertama, saya membuat blok kecil SQL dinamis untuk setiap bahasa:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
Ini menghasilkan 34 baris output seperti ini:
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)';
Saya menyalin output itu ke jendela permintaan baru, dan di atasnya, saya membuat kode ini, yang diharapkan akan mencoba untuk mengkonversi tanggal yang sama (tanggal 13 Maret) ke hari ke-3 dari bulan ke-13 dalam setidaknya satu kasus:
DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';
Tidak, setiap bahasa bekerja hanya menemukan di ydm
. Saya mencoba setiap format lainnya juga, dan juga setiap tipe data tanggal / waktu. 34 konversi sukses hingga 13 Maret, setiap saat.
Jadi, saya mengakui ke @AndriyM dan @ErikE bahwa, memang, ada format aman ke-3. Saya akan mengingat hal ini untuk posting selanjutnya, tetapi saya telah memukul drum tentang dua lainnya di begitu banyak tempat, saya tidak akan memburu mereka semua dan memperbaikinya sekarang.
Dengan ekstensi, Anda akan berpikir yang ini akan aman, tetapi tidak:
yyyyMMddThh:mm:ss.fff -- unseparated date, T separator
Saya pikir dalam setiap bahasa, ini akan menghasilkan yang setara dengan:
Msg 241, Level 16, State 1, Line 8
Conversion gagal ketika mengubah tanggal dan / atau waktu dari string karakter.
Untuk kelengkapan, ada format yang aman keempat, tetapi hanya aman untuk konversi ke jenis tanggal / waktu yang lebih baru ( date
, datetime2
, datetimeoffset
). Dalam kasus ini pengaturan bahasa tidak dapat mengganggu:
yyyy-MM-dd hh:mm:...
Namun, saya sangat menyarankan untuk tidak menggunakannya karena hanya berfungsi untuk jenis yang lebih baru, dan yang lama masih banyak digunakan, menurut pengalaman saya. Mengapa ada tanda hubung di tempat lain (atau bahkan dalam kode yang sama, jika tipe data berubah) Anda harus menghapusnya?
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);
Meskipun diberi string sumber yang sama , konversi menghasilkan hasil yang sangat berbeda:
März Juli März
Format yang berfungsi untuk datetime ( yyyyMMdd
) juga akan selalu bekerja untuk tanggal dan tipe baru lainnya. Jadi, IMHO, selalu gunakan itu. Dan mengingat format ketiga untuk tipe dengan tanggal / waktu ( yyyyMMdd hh:...
), ini sebenarnya akan memungkinkan Anda untuk lebih konsisten - bahkan jika komponen tanggal selalu sedikit kurang dapat dibaca.
Sekarang saya hanya perlu beberapa tahun, memberi atau menerima, untuk membiasakan mendemonstrasikan tiga format aman ketika saya berbicara tentang representasi string dari tanggal.