DateTime.Parse("AD3AD08") [2017-08-03 12:00:00 AM]¿Por qué esa cadena (que me parece una cadena hexadecimal normal) se analiza correctamente como una fecha? Puedo ver que el 3 y el 8 se analizan como meses y días. Pero de lo contrario no tiene sentido para mí.
tl; dr : puede usar lo que devuelve DateTimeFormatInfo.GetEraName / GetAbbreviatedEraName como delimitador, ignorando el caso. El orden es: día, mes, año (opcional).
Parece que siempre puede usar el nombre abreviado de la era actual del calendario o el nombre completo de la era como delimitador para los tokens DateTime. Para las culturas inglesas es AD o AD , por ejemplo, para las culturas alemanas es 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 AD 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 Curiosamente, no distingue entre mayúsculas y minúsculas, por lo que ad también funciona. Eso está documentado en DateTimeFormatInfo.GetEra :
El nombre de era es el nombre que usa un calendario para referirse a un período de tiempo contado a partir de un punto o evento fijo. Por ejemplo, "AD" o "CE" es la era actual en el calendario gregoriano. La comparación con eraName no distingue entre mayúsculas y minúsculas , por ejemplo, "AD" es equivalente a "ad".
El calendario gregoriano tiene solo una era, por lo que Calendar.GetEra(DateTime.Now) no es realmente necesario. Todavía no he encontrado más documentación.
Aquí hay algunas muestras que funcionan y se analizarán hasta la Navidad de 2017:
DateTime christmas = DateTime.Parse("ad25ad12ad2017ad"); christmas = DateTime.Parse("AD25ad12ad2017"); christmas = DateTime.Parse("25ad12ad2017AD"); christmas = DateTime.Parse("25ad12ad2017"); christmas = DateTime.Parse("AD25ad12ad2017"); christmas = DateTime.Parse("AD25ad12ad"); // current year is used christmas = DateTime.Parse("AD25ad12"); // current year is usedPuede confirmar que se trata de una era y no de un carácter codificado en UTF modificando el nombre de la era abreviado de la cultura (el nombre de la era se almacena en los campos privados DateTimeFormatInfo.m_abbrevEraNames y DateTimeFormatInfo.m_abbrevEnglishEraNames , y para la cultura invariable, el nombre de la era abreviado es una matriz de cadenas con un solo valor: "ANUNCIO"). El campo m_eraNames también almacena el nombre completo (no abreviado) de la era ("AD" para cultura invariable) que también se puede usar en lugar 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("AD03A.D.08", cul); // still works because we // did not modify non-abbreviated era name var date = DateTime.Parse("BLA03BLA08", cul); // this one works Ahora bien, por qué trata el nombre de la era de esa manera no es del todo obvio... Probablemente, después de encontrar dicho token, establece la fecha de la era y continúa analizando, por lo que sirve como separador en el sentido de que simplemente pasa a analizar el siguiente token después de este. La documentación para DateTime.Parse establece que:
Este método intenta analizar la cadena por completo y evitar lanzar una FormatException. Ignora los datos no reconocidos si es posible y completa la información faltante del mes, día y año con la fecha actual
Si bien esto no menciona nada sobre las eras, tal comportamiento se alinea con el diseño "evite lanzar FormatException siempre que sea posible".