没有标点符号的希腊月份使用 Date.ParseExact 转换为日期

Greek month with no punctuation convert to Date using Date.ParseExact

我有一个希腊日期 "08 Ιουνιου 2021",我想将其转换为 Date。这是不可能的,因为月份缺少一些标点符号。正确的月份是 "Ιουνίου",实际上通过下面的代码可以正常工作

var greek = new CultureInfo("el-GR").DateTimeFormat;
var dtFormat = DateTime.ParseExact("08 Ιουνίου 2021", "dd' 'MMMM' 'yyyy", greek, DateTimeStyles.None);

关于如何正确设置月份格式的任何想法?

我不知道这里问题的确切扩展 - 这些值是否来自数据库,或者这是否只是一次出现,或者是否需要比最初建立的更多 -

想法是在变音符号(在本例中为月)和非变音符号之间创建映射。

传递日期值 08 Ιουνιου 2021 后,我们会根据包含变音符号的月份映射对其进行检查。

比较由

完成
string.Compare(firstString, secondString, new CultureInfo("el-GR"), CompareOptions.IgnoreNonSpace);

来自 Msdn 文档 - IgnoreNonSpace:

表示字符串比较必须忽略非间距组合字符,如变音符号。 Unicode 标准将组合字符定义为与基本字符组合以产生新字符的字符。非间距组合字符在呈现时不会自行占据间距位置。

这 could/would 是一个潜在的修复方法:

    static string originalValue = "08 Ιουνιου 2021";
    static string[] currentMonth = originalValue.Split(' ');

    static List<string> monthMapping = new List<string>
        {
            //add others months mapping - I dont know how they are spelt -
            "Ιουνίου"
        };

    static void Main(string[] args)
    {
        DateTimeFormatInfo greek = new CultureInfo("el-GR").DateTimeFormat;

        foreach (string month in monthMapping)
        {
            if( string.Compare(currentMonth[1], month, new CultureInfo("el-GR") , CompareOptions.IgnoreNonSpace) == 0)
            {
                var dtFormat = DateTime.ParseExact($"08 {month} 2021", "dd' 'MMMM' 'yyyy", greek, DateTimeStyles.None);
            }

        }
    }

您可以尝试规范化月份名称,使用不区分变音符号的比较从 CultureInfo.DateTimeFormat.MonthGenitiveNames 集合中检索正确的月份名称,因为在某些文化中,属格名称与主格名称不同(日期是以以下形式呈现:8th of June, 2021).

一个String.Compare() overload accepts both CultureInfo and CompareOptions个参数。
IgnoreNonSpace 标志:表示字符串比较必须忽略非间距组合字符,例如变音符号。 [...]。 这允许在 MonthGenitiveNames 集合和 return 相应的专有名称中搜索月份名称,忽略缺失的变音符号。

然后可以将 标准化的 日期与提供的 CultureInfo 一起传递给 DateTime.TryParse(),以提取 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 个或更多部分组成的月份名称,为了使该方法更通用并将相同的过程应用于 Abbreviated Month Genitive 名称,可以修改此方法以解析输入日期的方式略有不同,还允许指定是否以短格式提供月份名称。

日期格式可以由这三部分组成:

  1. 代表月中日或年的数值
  2. 月份部分,属名,长格式字符串 (MMMM) 或短格式字符串 (MMM)
  3. 表示年或月日的数值

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"));
    }
}