在C#中将非常长的日期格式解析为DateTime

Ben*_*dge 2 c# datetime parsing

我如何将以下字符串日期解析为C#中的DateTime对象:

"1970年1月1日星期四"

这来自XML提要,而DateTime.Parse似乎不喜欢它在en-GB语言环境中.饲料只会来自英国的服务器,所以我不担心全球化问题

我最初的蛮力方法是:

  • 删除包括逗号在内的所有内容,以及留下"1970年1月1日"的尾随空格
  • 然后根据需要删除"st","nd","rd"或"th"以留下"1970年1月1日"
  • 然后将月份转换为其数字等价物,留下"1 1 1970"
  • 然后用"/"替换空格以获得"1/1/1970"

我敢肯定必须有更优雅的方式吗?我无法使DateTime.Prse或Datetime.ParseExact工作

Jon*_*eet 6

我不相信DateTime解析知道关于序数的任何事情,但它应该能够处理其他一切.所以你可以使用:

public static string RemoveOrdinals(string input)
{
    // Ugly but oh so simple.
    return input.Replace("0th", "0")
                .Replace("1st", "1")
                .Replace("2nd", "2")
                .Replace("3rd", "3")
                .Replace("11th", "11") // Need to handle these separately...
                .Replace("12th", "12")
                .Replace("13th", "13")
                .Replace("4th", "4")
                .Replace("5th", "5")
                .Replace("6th", "6")
                .Replace("7th", "7")
                .Replace("8th", "8")
                .Replace("9th", "9");
}
Run Code Online (Sandbox Code Playgroud)

然后:

string text = RemoveOrdinals(text);
DateTime date = DateTime.ParseExact(text, "dddd, d MMMM yyyy",
                                    CultureInfo.GetCulture("en-GB"));
Run Code Online (Sandbox Code Playgroud)

(作为一个快速插件,当然你只需要一个日期而不是日期/时间.不幸的是.NET没有一种类型来表示 - 但你可以LocalDate在我的Noda Time库中使用.我们也不处理序数 - 但是,无论如何 - 所以你仍然需要额外的方法.如果你想看到相关的代码,请告诉我.)


RJ *_*han 5

只是为了提供一个略有不同的看法,并让您了解一些其他选择; 你可以指定DateTime.Parse(或我的例子中的TryParse)的格式来解决这样的情况,而不试图通过String.Replace调用等将字符串"预格式化"为其他内容;

public DateTime ParseOrdinalDateTime(string dt)
{
    string[] expectedFormats = 

    DateTime d;
    if (DateTime.TryParseExact(dt, "dddd, d\"st\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;
    if (DateTime.TryParseExact(dt, "dddd, d\"nd\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;
    if (DateTime.TryParseExact(dt, "dddd, d\"rd\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;
    if (DateTime.TryParseExact(dt, "dddd, d\"th\" MMMM yyyy", null, DateTimeStyles.None, out d))
        return d;

    throw new InvalidOperationException("Not a valid DateTime string");
}
Run Code Online (Sandbox Code Playgroud)

我提出这种方法的原因是它非常清楚地列出了你的输入期望,并且包含了单个方法的行为.如果格式更改,您可以在此处指定不同的格式字符串,并考虑新的日期时间字符串结构.

或者,考虑到以下评论,上述内容略有不同;

private static DateTime ParseOrdinalDateTime(string dt)
{
    string[] expectedFormats = new[]
    {
        "dddd, d'st' MMMM yyyy",
        "dddd, d'nd' MMMM yyyy",
        "dddd, d'rd' MMMM yyyy",
        "dddd, d'th' MMMM yyyy"
    };

    try
    {
        return DateTime.ParseExact(dt, expectedFormats, null, DateTimeStyles.None);
    }
    catch (Exception e)
    {
        throw new InvalidOperationException("Not a valid DateTime string", e);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:我捕获并抛出上面的InvalidOperationException的唯一原因是保护调用者不必catch Exception处理DateTime.ParseExact可能抛出的异常.您可以轻松修改此API.

  • 我还建议明确指定文化 - 我们知道它的意义,为什么要依赖线程的当前文化? (2认同)