2017-04-11 44 views
31
DateTime.Parse("AD3AD08") 

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

Dlaczego ten ciąg (który wygląda jak zwykły ciąg szesnastkowy do mnie) zostanie pomyślnie przeanalizowany jako data? Widzę, że 3 i 8 są analizowane jako miesiące i dni. Ale w przeciwnym razie nie ma to dla mnie sensu.Dlaczego AD3AD08 reprezentuje poprawną datę w środowisku .NET?

+0

działa, jeśli mogę zmienić obecną kulturę 'en-US' lub' en-GB', nie wiem dlaczego albo –

+0

Nawet dla 'DateTime.Parse ("AD3AD08", CultureInfo.InvariantCulture); ' – xanatos

+0

To jest nazwa ery (AD = anno domini) – xanatos

Odpowiedz

19

tl; dr: Można wykorzystać to, co DateTimeFormatInfo.GetEraName/GetAbbreviatedEraName zwrot jako separatora, ignorując sprawę. Kolejność: dzień, miesiąc, rok (opcjonalnie).


Wydaje zawsze można użyć kalendarza aktualny era's abbreviated name lub full era-name jako ogranicznik dla tokenów DateTime. W przypadku angielskich hodowli jest to AD lub A.D., np. dla kultur niemieckich jest to 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 

ciekawe jest rozróżniana wielkość liter, więc ad prace również. Która jest udokumentowana w DateTimeFormatInfo.GetEra:

Nazwa era to nazwa kalendarz używa się w odniesieniu do okresu liczony od ustalonego punktu lub zdarzenia. Na przykład "A.D." lub "C.E." jest obecna era kalendarza gregoriańskiego. Porównanie z eraName jest niewrażliwe na wielkość liter, na przykład "A.D." jest równoważne "a.d.".

Kalendarz gregoriański ma tylko jedną erę, więc Calendar.GetEra(DateTime.Now) nie jest naprawdę konieczne. Nie znalazłem jeszcze żadnej dokumentacji.

Oto kilka próbek, że wszystkie prace i będzie analizowany na Boże Narodzenie 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 
+0

Jak wskazuje to łącze, obecna era jest znana jako "AD" * lub * CE " a mimo to nie możemy użyć "CE" jako "separatora". –

+0

Zgodnie ze źródłem odniesienia, twoja odpowiedź jest prawidłowa. Zastanawiam się tylko, dlaczego taki niechlujny wybór. Chodzi mi o to, że zaakceptowanie ery * po * dacie miałoby sens, ale zaakceptowanie jej w dowolnym miejscu ... nie byłoby mylące? –

+2

@Damien_The_Unbeliever: można użyć tylko zwrotu 'GetEraName' lub' GetAbbreviatedEraName', który jest 'A.D.' /' AD'. –

9

Można potwierdzić, że jest to era, a nie jakiś UTF kodowany charakter modyfikując kultury skrócona nazwa era (nazwa ery jest przechowywany w DateTimeFormatInfo.m_abbrevEraNames i DateTimeFormatInfo.m_abbrevEnglishEraNames pól prywatnych oraz dla kultury niezmiennego skrócona nazwa era jest tablicę ciągów z tylko jednej wartości - "OGŁOSZENIE"). Pole m_eraNames przechowuje również pełną (nieskróconą) nazwę ery ("A.D." dla kultury niezmienniczej), która może być również używana zamiast "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 

Teraz dlaczego traktuje nazwę era tak nie jest oczywiste ... Prawdopodobnie po spełnieniu takich tokena to ustawia datę erę i nadal parsowania, więc służy jako separator w pewnym sensie po prostu przenosi się do analizowania następny znak po tym. Dokumentacja dla DateTime.Parse stwierdza:

Metoda ta próbuje zanalizować ciąg całkowicie i unikać rzucania FormatException. Ignoruje nierozpoznane dane, jeśli to możliwe i wypełnia brakuje miesiąc, dzień i informacje o rok z aktualną datą

Choć nie wspomina nic o epok - takie zachowanie jest wyrównany „unikać rzucania FormatException miarę możliwości” design.