首页 > 解决方案 > 使用 Date.ParseExact 将没有标点符号的希腊月份转换为日期

问题描述

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

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

任何想法如何正确格式化月份?

标签: c#datedatetime-format

解决方案


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

String.Compare ()重载接受 CultureInfo 和CompareOptions参数。标志:
指示字符串比较必须忽略非间距组合字符,例如变音符号。[...]。这允许在集合中搜索月份名称,忽略缺少的变音符号,并返回相应的正确名称。IgnoreNonSpaceMonthGenitiveNames

然后可以将标准化日期与提供的 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名称,可以修改此方法以以稍微不同的方式解析输入日期和还允许指定是否以短格式提供月份名称。

日期格式可以由以下 3 部分组成:

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

推荐阅读