32 votes

Pourquoi AD3AD08 représente-t-il une date valide dans le cadre de .NET ?

DateTime.Parse("AD3AD08")

[2017-08-03 12:00:00 AM]

Pourquoi cette chaîne (qui me semble être une chaîne hexagonale normale) est-elle analysée avec succès comme une date ? Je peux voir que le 3 et le 8 sont analysés comme des mois et des jours. Mais sinon, cela n'a aucun sens pour moi.

20voto

Tim Schmelter Points 163781

en résumé : Vous pouvez utiliser ce que DateTimeFormatInfo.GetEraName / GetAbbreviatedEraName comme délimiteur, sans tenir compte de la casse. L'ordre est le suivant : jour, mois, année (facultatif).


Il semble que vous pouvez toujours utiliser l'actuel calendrier nom abrégé de l'ère o nom complet de l'époque comme délimiteur pour les jetons DateTime. Pour les cultures anglaises, c'est AD o A.D. Par exemple, pour les cultures allemandes, il s'agit de n. Chr. .

var enCulture = new CultureInfo("en-GB");
System.Threading.Thread.CurrentThread.CurrentCulture = enCulture;
var fi = enCulture.DateTimeFormat;
int currentEra = enCulture.Calendar.GetEra(DateTime.Now);
var eraName = fi.GetEraName(currentEra);
var shortEra = fi.GetAbbreviatedEraName(currentEra);
var date = DateTime.Parse($"{shortEra}3{shortEra}08"); // AD or A.D. works

var deCulture = new CultureInfo("de-DE");
System.Threading.Thread.CurrentThread.CurrentCulture = deCulture;
fi = deCulture.DateTimeFormat;
currentEra = deCulture.Calendar.GetEra(DateTime.Now);
eraName = fi.GetEraName(currentEra);
shortEra = fi.GetAbbreviatedEraName(currentEra);
date = DateTime.Parse($"{shortEra}3{shortEra}08");  // n. Chr. works

Il est intéressant de noter qu'elle n'est pas sensible à la casse, donc ad fonctionne également. Cela est documenté dans DateTimeFormatInfo.GetEra :

Le nom de l'ère est le nom qu'un calendrier utilise pour faire référence à une période de temps. à partir d'un point fixe ou d'un événement. Par exemple, "A.D." ou "C.E." est le nom d'une époque. l'ère actuelle dans le calendrier grégorien. La comparaison avec eraName est insensible à la casse Par exemple, "A.D." est équivalent à "a.d.".

Le calendrier grégorien n'a qu'une seule ère, donc Calendar.GetEra(DateTime.Now) n'est pas vraiment nécessaire. Je n'ai pas encore trouvé de documentation supplémentaire.

Voici quelques échantillons qui fonctionnent tous et qui seront analysés à Noël 2017 :

DateTime christmas  = DateTime.Parse("ad25ad12ad2017ad");
christmas = DateTime.Parse("AD25ad12ad2017");
christmas = DateTime.Parse("25ad12ad2017AD");
christmas = DateTime.Parse("25ad12ad2017");
christmas = DateTime.Parse("A.D.25ad12ad2017");
christmas = DateTime.Parse("A.D.25ad12ad");  // current year is used
christmas = DateTime.Parse("A.D.25ad12");    // current year is used

9voto

Evk Points 17804

Vous pouvez confirmer qu'il s'agit bien de era et non d'un quelconque caractère codé UTF en modifiant le nom abrégé de era de la culture (le nom de era est stocké dans le fichier DateTimeFormatInfo.m_abbrevEraNames y DateTimeFormatInfo.m_abbrevEnglishEraNames champs privés, et pour la culture invariante, le nom abrégé de l'ère est un tableau de chaînes de caractères avec une seule valeur - "AD"). m_eraNames Le champ stocke également le nom complet (non abrégé) de l'ère ("A.D." pour une culture invariante) qui peut également être utilisé à la place de "AD".

var cul = (CultureInfo) CultureInfo.InvariantCulture.Clone();                        
// set DateTimeFormatInfo.AbbreviatedEraNames to "BLA"
typeof(DateTimeFormatInfo).GetField("m_abbrevEraNames", BindingFlags.Instance | BindingFlags.NonPublic)
    .SetValue(cul.DateTimeFormat, new string[] {"BLA"});
// set DateTimeFormatInfo.AbbreviatedEnglishEraNames to "BLA"
typeof(DateTimeFormatInfo).GetField("m_abbrevEnglishEraNames", BindingFlags.Instance | BindingFlags.NonPublic)
    .SetValue(cul.DateTimeFormat, new string[] { "BLA" });

var date = DateTime.Parse("AD03AD08", cul); // now it fails
var date = DateTime.Parse("A.D.03A.D.08", cul); // still works because we
// did not modify non-abbreviated era name
var date = DateTime.Parse("BLA03BLA08", cul); // this one works

Maintenant, pourquoi il traite le nom de l'ère comme ça n'est pas tout à fait évident... Probablement qu'après avoir rencontré un tel token, il fixe la date era et continue le parsing, donc il sert de séparateur dans un sens, il passe juste au parsing du prochain token après celui-ci. Documentation pour DateTime.Parse déclare que :

Cette méthode tente d'analyser complètement la chaîne de caractères et d'éviter de déclencher un FormatException. Elle ignore les données non reconnues si possible et remplit les éléments suivants les informations manquantes sur le mois, le jour et l'année avec la date actuelle.

Bien que cela ne mentionne rien au sujet des périodes, un tel comportement s'aligne sur la conception consistant à " éviter de lancer une FormatException chaque fois que cela est possible ".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X