Вы можете попытаться нормализовать название месяца, используя диакритическое c нечувствительное сравнение, чтобы получить правильное название месяца из коллекции CultureInfo.DateTimeFormat.MonthGenitiveNames , поскольку в некоторых культурах родительное имя отличается от именительного падежа (дата представлена в форме: 8th of June, 2021
).
A String.Compare () перегрузка принимает как аргументы CultureInfo, так и CompareOptions . Флаг IgnoreNonSpace
: Указывает, что при сравнении строк должны игнорироваться непробельные объединяющие символы, например диакритические знаки. [...] . Это позволяет искать название месяца, игнорируя отсутствующие диакритические знаки, в коллекциях MonthGenitiveNames
и возвращать соответствующее собственное имя.
Затем нормализованная дата может быть передана в DateTime.TryParse () вместе с предоставленной CultureInfo для извлечения объекта DateTime.
Пример вызова метода:
var normalizedDateTime = NormalizeMonthDiacritics(new CultureInfo("el-GR"), "08 Ιουνιου 2021");
using System.Globalization;
using System.Linq;
internal DateTime NormalizeMonthDiacritics(CultureInfo culture, string date)
{
string[] inputDateParts = date.Split();
inputDateParts[1] = culture.DateTimeFormat.MonthGenitiveNames.FirstOrDefault(month =>
string.Compare(inputDateParts[1], month, culture, CompareOptions.IgnoreNonSpace) == 0)
?? inputDateParts[1];
string normalizedDate = string.Join(" ", inputDateParts);
if (DateTime.TryParse(normalizedDate, culture, DateTimeStyles.None, out DateTime dtm)) {
return dtm;
}
else {
throw new ArgumentException("The provided date cannot be normalized",
new Exception("Month Genitive form not available"));
}
}
Поскольку по крайней мере 37 культур используют имена месяцев, состоящие из 2 или более частей, чтобы сделать метод более универсальным c, а также применить ту же процедуру к сокращенным родительным падежам именам, этот метод может быть изменен, чтобы анализировать дату ввода немного иначе, а также позволяет указать, предоставляется ли название месяца в коротком формате.
Формат даты может состоять из этих 3 частей:
- Numeri c значение, представляющее либо день месяца, либо год
- часть месяца, родительное имя, либо в длинной строке формата (
MMMM
), либо в коротком формате (MMM
) - Numeri c значение, представляющее год или день месяца
DateTime.TryParse()
может обрабатывать формат DateTime обоими способами.
Вызовите этот измененный метод следующим образом :
var culture = new CultureInfo("sah-RU");
string date = "2020 атырдьах ыиын 08"; // <= Should be атырдьах ыйын
var normalizedDateTime = NormalizeMonthDiacritics(culture, date, false);
Модифицированный метод:
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
internal DateTime NormalizeMonthDiacritics(CultureInfo culture, string date, bool monthShortForm = false)
{
string pattern = @"(\d+)\s+(.*?)\s+(\d+)";
var parts = Regex.Match(date, pattern, RegexOptions.CultureInvariant | RegexOptions.Singleline)
.Groups.OfType<Capture>().Skip(1).Take(3).Select(c => c.Value).ToArray();
var monthNames = monthShortForm
? culture.DateTimeFormat.AbbreviatedMonthGenitiveNames
: culture.DateTimeFormat.MonthGenitiveNames;
parts[1] = monthNames.FirstOrDefault(month =>
string.Compare(parts[1], month, culture, CompareOptions.IgnoreNonSpace) == 0)
?? parts[1];
string normalizedDate = string.Join(" ", parts);
if (DateTime.TryParse(normalizedDate, culture, DateTimeStyles.None, out DateTime dtm)) {
return dtm;
}
else {
throw new ArgumentException("The provided date cannnot be normalized",
new Exception("Month Genitive form not available"));
}
}