Hangi tarih / saat değişmez biçimleri LANGUAGE ve DATEFORMAT için güvenlidir?


24

O, birçok tarih / saat biçimlerini göstermek kolaydır diğer aşağıdaki iki yüzünden SET DİL, SET DATEFORMAT veya oturum açma adı varsayılan dile yanlış yorumlanmasına karşı savunmasız olduklarından daha:

yyyyMMdd                 -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff  -- date dash separated, date/time separated by T 

Bu format bile T olmadan geçerli bir ISO 8601 formatına benzeyebilir , ancak birkaç dilde başarısız oluyor:

DECLARE @d varchar(32) = '2017-03-13 23:22:21.020';

SET LANGUAGE Deutsch;
SELECT CONVERT(datetime, @d);

SET LANGUAGE Français;
SELECT CONVERT(datetime, @d);

Sonuçlar:

Die Spracheneinstellung ezme auf Deutsch geändert.

Msg 242, Seviye 16, Devlet 3
Bei der Konvertierung varchar-einen tarihte Datentyps-Datentyp liegt der Wert außerhalb des gültigen Bereichs.

Le Paramétre de France, Français'da.

Msg 242, Seviye 16, Devlet 3
La dönüşümü türüne göre değiştirilemez, aynı zamanda değiştirilemeyen türler de sınırsızdır.

Şimdi, bunlar, ingilizce olarak, bir tarih bileşeni oluşturmak için ay ve günü aktarmışım gibi başarısız oluyor yyyy-dd-mm:

DECLARE @d varchar(32) = '2017-13-03 23:22:21.020';

SET LANGUAGE us_english;
SELECT CONVERT(datetime, @d);

Sonuç:

Mesaj 242, Seviye 16, Durum 3
Bir varchar veri tipinin bir tarih-saat veri tipine dönüştürülmesi, aralık dışı bir değere yol açtı.

(Bu sizin için "iyi" olan Microsoft Access değildir ve sizin için yer değiştirmeyi düzeltir. Ayrıca, bazı durumlarda da benzer hatalar olabilir SET DATEFORMAT ydm;- bu sadece bir dil değil , bu durumun en yaygın senaryosudur. kırılmalar oluyor - ve her zaman fark edilmiyorlar çünkü bazen hata değiller, sadece 7 Ağustos 8 Temmuz oldu ve kimse fark etmedi.)

Öyleyse, soru:

Artık bir sürü güvenli olmayan format olduğunu biliyorum, herhangi bir dil ve tarih formatı birleşimi verildiğinde güvenli olacak başka formatlar var mı?

Yanıtlar:


26

Gelen belgeler , çok açık bir şekilde sadece güvenli biçimleri çok sorunun başlayan gösterişe olanlardır belirtilmektedir:

yyyyMMdd                 -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff  -- date dash separated, date/time separated by T 

Ancak, son zamanlarda dikkatime, herhangi bir dile ya da tarih formatı ayarına eşit derecede bağışık olan üçüncü bir format olduğuna dikkat çekildi:

yyyyMMdd hh:mm:ss.fff    -- unseparated date, no T separator

TL; DR: Bu doğru. İçin datetimeve smalldatetime.

Daha uzun versiyon için ve okuma alacağınız kadar kanıt için okumaya devam edin.


Bunu açıklayan bir boşluk var - ana metin gövdesi yyyyMMdd hh:...aktarılan dil veya tarih formatı yorumlamalarından güvenli bir format olarak kabul edemezken, böyle bir dizginin tarih kısmının tarih formatı ayarlarına bağlı olarak doğrulanmadığını söyleyen küçük bir bulanıklık var:

görüntü tanımını buraya girin

Belgeleri, sadece kendi sözleriyle almamın aksine, aksine. Biraz şüpheci olduğumu söyleyebilirsin. Dil burada da belirsizdir - sadece bunun alanı ve yeri açıkça söylememekle (tarihin ve saatin birleşimi olduğunu) (bildiğim kadarıyla bir taşıma dönüşü olabilir) olduğunu belirtir. Aynı zamanda çok dilli olmadığını, yani belli dillerde başarısız olabileceği anlamına geliyor, ama bunun da yanlış olduğunu kısaca anlayacağız.

Bu nedenle, hiçbir dil / tarih formatı kombinasyonunun bu belirli formatın başarısız olamayacağını kanıtlamaya başladım.

İlk önce, her dil için küçük bir dinamik SQL bloğu oluşturdum:

EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';

Bu, bunun gibi 34 satır çıktı üretti:

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)';    

Bu çıktıyı yeni bir sorgu penceresine kopyaladım ve üstünde, en azından bir durumda aynı tarihi (13 Mart) 13 ayın 3. gününe dönüştürmeyi deneyecek olan bu kodu oluşturdum:

DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';

Hayır, her dilin işe yaramadı ydm. Diğer tüm formatları ve ayrıca her tarih / saat veri türünü denedim. Her zaman 13 Mart'a 34 başarılı dönüşüm.

Bu yüzden, @AndriyM ve @ErikE'e, gerçekten de 3. güvenli bir formatın olduğunu kabul ediyorum. Gelecekteki gönderiler için bunu aklımda tutacağım, ama diğer birçok yerdeki davulları pek çok yerde çarptım, hepsini avlamayacağım ve şimdi düzeltmeyeceğim.


Ek olarak, bunun güvenli olacağını düşünürsünüz, ama hayır:

yyyyMMddThh:mm:ss.fff    -- unseparated date, T separator

Her dilde bunun eşdeğerini vereceğini düşünüyorum:

Mesaj 241, Seviye 16, Durum 1, Satır 8
Dönüştürme , tarih ve / veya saati karakter dizgisinden dönüştürürken başarısız oldu.


Bütünlüğü sağlamak için, orada dördüncü güvenli biçimidir, ancak yeni tarih / saat türlerine dönüşüm için yalnızca güvenlidir ( date, datetime2, datetimeoffset). Bu durumlarda dil ayarları karışmaz:

yyyy-MM-dd hh:mm:...

Bununla birlikte, kullanımına karşı şiddetle tavsiye ediyorum, çünkü sadece yeni tipler için işe yarıyor ve eskiler de benim deneyimimde hala büyük miktarda kullanılıyor. Neden başka yerlerde (ya da veri türü değişirse aynı kodda, aslında aynı kodda) bunları kaldırmak zorunda kaldığınızda neden çizgiler var?

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);

Aynı kaynak dizeye rağmen , dönüşümler oldukça farklı sonuçlar verdi:

März    Juli    März

Datetime ( yyyyMMdd) için çalışan biçim her zaman tarih ve diğer yeni türler için de çalışır. Yani, IMHO, sadece her zaman bunu kullanın. Ve date / time ( yyyyMMdd hh:...) tipindeki türler için üçüncü format verilmişse , bu aslında daha tutarlı olmanıza izin verir - tarih bileşeni her zaman biraz daha az okunabilir olsa bile.


Şimdi , tarihlerin sicim temsili hakkında konuşurken üç güvenli formatı gösterme alışkanlığına girmek bana sadece birkaç yıl sürecek .


Üçüncü biçim olabilir değil mi olmak yeni bir dil bazı gelecekteki bir sürümde SQL Server eklendiğinde güvensiz?
Kuba Wyrostek

@Kuba Microsoft’un bu konuda derslerini aldığından eminim. Birileri bu dillerin hepsinin yyyy-gg-MM'yi yorumlaması için oldukça zayıf bir karar vermiş, yeryüzünde kimsenin bilerek kullanmadığını sanmıyorum.
Aaron Bertrand
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.