Dans la documentation , il est très explicitement indiqué que les seuls formats sûrs sont ceux que j'ai montrés au tout début de la question:
yyyyMMdd -- unseparated, date only
yyyy-MM-ddThh:mm:ss.fff -- date dash separated, date/time separated by T
Cependant, il a été récemment porté à mon attention qu'il existe un troisième format qui est également immunisé contre tous les paramètres de langue ou de format de date:
yyyyMMdd hh:mm:ss.fff -- unseparated date, no T separator
TL; DR: C'est vrai. Pour datetime
et smalldatetime
.
Lisez la suite pour la version plus longue, et pour autant de preuves que vous allez en avoir.
Il y a une faille qui explique cela - bien que le corps du texte principal ne reconnaisse pas yyyyMMdd hh:...
un format à l'abri des interprétations de langue transposée ou de format de date, il y a un petit texte expliquant que la partie date d'une telle chaîne n'est pas validée en fonction des paramètres de format de date:
C'est assez différent de moi de prendre la documentation au mot, généralement. Vous pouvez dire que je suis un peu sceptique. Et le langage est ambigu ici aussi - il indique simplement qu'il s'agit de la combinaison de la date et de l'heure, sans appeler explicitement l'espace (cela pourrait être un retour chariot, pour autant que je sache). Il indique également qu'il n'est pas multilingue, ce qui signifie qu'il pourrait échouer dans certaines langues, mais nous découvrirons sous peu que c'est également incorrect.
J'ai donc voulu prouver qu'aucune combinaison langue / format de date ne pouvait faire échouer ce format spécifique.
Tout d'abord, j'ai créé un petit bloc de SQL dynamique pour chaque langue:
EXEC sys.sp_executesql @sql, N'@lang sysname', N'us_english';
Cela a produit 34 lignes de sortie comme ceci:
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)';
J'ai copié cette sortie dans une nouvelle fenêtre de requête, et au-dessus, j'ai généré ce code, qui devrait, espérons-le, essayer de convertir cette même date (le 13 mars) au 3ème jour du 13ème mois dans au moins un cas:
DECLARE @sql nvarchar(max) = N'
SET LANGUAGE @lang;
SET DATEFORMAT ydm;
SELECT @@LANGUAGE, CONVERT(datetime, ''20170313 23:22:21.020'');';
Non, toutes les langues travaillées se trouvent ydm
. J'ai également essayé tous les autres formats, ainsi que tous les types de données date / heure. 34 conversions réussies au 13 mars, à chaque fois.
Donc, je concède à @AndriyM et @ErikE qu'il existe en effet un troisième format sûr. Je garderai cela à l'esprit pour les prochains articles, mais j'ai pilonné les tambours des deux autres à tellement d'endroits, je ne vais pas tous les traquer et les corriger maintenant.
Par extension, vous penseriez que celui-ci serait sûr, mais non:
yyyyMMddThh:mm:ss.fff -- unseparated date, T separator
Je pense que dans toutes les langues, cela donnera l'équivalent de:
Msg 241, niveau 16, état 1, ligne 8 La
conversion a échoué lors de la conversion de la date et / ou de l'heure à partir d'une chaîne de caractères.
Pour être complet, il existe un quatrième format sûr, mais il n'est sûr que pour les conversions vers les types de date / heure les plus récents ( date
,datetime2
, datetimeoffset
). Dans ces cas, les paramètres de langue ne peuvent pas interférer:
yyyy-MM-dd hh:mm:...
Cependant, je recommande fortement contre son utilisation car il ne fonctionne que pour les nouveaux types, et les anciens sont encore très utilisés, selon mon expérience. Pourquoi avoir les tirets là où partout ailleurs (ou en fait dans ce même code, si le type de données change) vous devez les supprimer?
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ême compte tenu de la même chaîne source, les conversions ont donné des résultats assez différents:
März Juli März
Le format qui fonctionne pour datetime ( yyyyMMdd
) sera également toujours pour la date et les autres nouveaux types. Donc, à mon humble avis, utilisez toujours cela. Et étant donné le troisième format pour les types avec date / heure ( yyyyMMdd hh:...
), cela vous permettra en fait d'être plus cohérent - même si le composant date est toujours un peu moins lisible.
Maintenant, il me faudra juste quelques années, à donner ou à prendre, pour prendre l'habitude de démontrer les trois formats sûrs lorsque je parle de la représentation sous forme de chaîne des dates.