DateTime.Parse("AD3AD08")
[2017-08-03 12:00:00 AM]
Why does that string (which looks like just a normal hex string to me) get parsed successfully as a date? I can see the 3 and the 8 get parsed as months and days. But otherwise it doesn't make sense to me.
tl;dr: You can use what DateTimeFormatInfo.GetEraName
/GetAbbreviatedEraName
return as delimiter, ignoring the case. The order is: day, month, year (optional).
It seems you can always use the calendar's current era's abbreviated name or full era-name as delimiter for the DateTime tokens. For english cultures it is AD
or A.D.
, e.g. for german cultures it is 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
Interestingly it is case-insensitive, so ad
works also. That is documented in DateTimeFormatInfo.GetEra
:
The era name is the name a calendar uses to refer to a period of time reckoned from a fixed point or event. For example, "A.D." or "C.E." is the current era in the Gregorian calendar. The comparison with eraName is case-insensitive, for example, "A.D." is equivalent to "a.d.".
The gregorian calendar has only one era, so Calendar.GetEra(DateTime.Now)
isn't really necessary. I haven't found any further documentation yet.
Here are some samples that all work and will be parsed to christmas 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
You can confirm that this is era and not some UTF encoded character by modifying culture abbreviated era name (era name is stored in DateTimeFormatInfo.m_abbrevEraNames
and DateTimeFormatInfo.m_abbrevEnglishEraNames
private fields, and for invariant culture abbreviated era name is string array with just one value - "AD"). m_eraNames
field also stores full (non-abbreviated) era name ("A.D." for invariant culture) which can also be used instead of "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
Now why it treats era name like that is not quite obvious... Probably after meeting such token it sets date era and continues parsing, so it serves as separator in a sense it just moves to parsing next token after this one. Documentation for DateTime.Parse
states that:
This method attempts to parse string completely and avoid throwing a FormatException. It ignores unrecognized data if possible and fills in missing month, day, and year information with the current date
While this does not mention anything about eras - such behavior aligns with "avoid throwing FormatException whenever possible" design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With