如何在C#中将月份名称(字符串)解析为整数以进行比较?

104

我需要能够比较我在一个数组中拥有的一些月份名称。

如果有像这样的直接方式就好了:

Month.toInt("January") > Month.toInt("May")

我在谷歌上搜索了一下,似乎唯一的方法是编写自己的方法,但这似乎是一个足够常见的问题,我认为它已经在.Net中实现了,有人之前做过吗?

15个回答

198

DateTime.ParseExact(monthName, "MMMM", CultureInfo.CurrentCulture ).Month

尽管如此,针对您的目的,最好创建一个将月份名称映射到其值的Dictionary<string, int>


12
在决定使用CultureInfo.CurrentCulture还是CultureInfo.InvariantCulture时,请务必考虑https://dev59.com/inVC5IYBdhLWcg3wixw0。 - Rasmus Faber

24

你可以这样做:

Convert.ToDate(month + " 01, 1900").Month

20
如果您使用多个人建议的DateTime.ParseExact()方法,请仔细考虑应用程序在非英语环境下运行时您想要发生什么!
在丹麦,ParseExact("Januar", ...)ParseExact("January", ...)中哪一个应该起作用,哪一个应该失败?
这将取决于CultureInfo.CurrentCultureCultureInfo.InvariantCulture之间的区别。

10

一个简单的解决方案是创建一个包含名称和值的字典。然后使用Contains()方法就可以找到正确的值。

Dictionary<string, string> months = new Dictionary<string, string>()
{
                { "january", "01"},
                { "february", "02"},
                { "march", "03"},
                { "april", "04"},
                { "may", "05"},
                { "june", "06"},
                { "july", "07"},
                { "august", "08"},
                { "september", "09"},
                { "october", "10"},
                { "november", "11"},
                { "december", "12"},
};
foreach (var month in months)
{
    if (StringThatContainsMonth.ToLower().Contains(month.Key))
    {
        string thisMonth = month.Value;
    }
}

9

您可以使用月份枚举:

public enum Month
{
    January,
    February,
    // (...)
    December,
}    

public Month ToInt(Month Input)
{
    return (int)Enum.Parse(typeof(Month), Input, true));
}

我不完全确定enum.Parse()的语法,不过。


1
它需要是“public Month ToInt(string Input) {...}”,但除此之外它是正确的。 - James Curran
2
我知道这是一个旧评论,但我想指出你应该从1开始枚举,例如public enum Month { January = 1, Feburary },并且将其转换为int而不是Month。 - eth0
@eth0:哎呀,你说得对。已经更正了,感谢指出;-) - Treb

9
您可以使用DateTime.Parse方法获取一个DateTime对象,然后检查它的Month属性。像这样做:
您可以使用 DateTime.Parse 方法来获取 DateTime 对象,然后检查其 Month 属性。如下所示:
int month = DateTime.Parse("1." + monthName + " 2008").Month;

技巧在于构建一个有效的日期来创建DateTime对象。

8
您不需要创建一个DateTime实例来完成此操作。只需要这样简单的代码:
public static class Month
{
    public static int ToInt(this string month)
    {
        return Array.IndexOf(
            CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
            month.ToLower(CultureInfo.CurrentCulture))
            + 1;
    }
}

我正在使用da-DK文化运行,因此这个单元测试通过:

[Theory]
[InlineData("Januar", 1)]
[InlineData("Februar", 2)]
[InlineData("Marts", 3)]
[InlineData("April", 4)]
[InlineData("Maj", 5)]
[InlineData("Juni", 6)]
[InlineData("Juli", 7)]
[InlineData("August", 8)]
[InlineData("September", 9)]
[InlineData("Oktober", 10)]
[InlineData("November", 11)]
[InlineData("December", 12)]
public void Test(string monthName, int expected)
{
    var actual = monthName.ToInt();
    Assert.Equal(expected, actual);
}

我将把它留给读者作为一个练习,让你创建一个重载,可以传入一个明确的CultureInfo。


不错的ToLower()使用 - 我没有意识到其中一个重载会转换字符串,使用指定文化的大小写规则,尽管公平地说,从方法名称中并不明显它可能提供该功能。 - David Clarke
1
好的,我一直在使用LINQPad进行测试,但是我无法在我的“CurrentCulture”中使其工作。 "January".ToLower(CultureInfo.CurrentCulture).Dump();"January".ToLower(new CultureInfo("en-NZ")).Dump(); 都输出 january,但是月份名称在 CurrentCulture.DateTimeFormat.MonthNames 中是大写的。 - David Clarke
1
@DavidClarke 嗯,是的,您正在调用名为ToLower的函数 :) 实际上,在我的代码中存在一个轻微的逻辑缺陷,因为在da-DK中给出月份名称时全部使用小写。因此,要么不应将输入转换为小写,要么还应将所有月份名称都转换为小写 - 具体取决于是否需要进行大小写不敏感的匹配。 - Mark Seemann
1
是的,我曾经解释过文档“使用指定文化的大小写规则”,意思是它会按照CultureInfo大写化月份和日期等。这在你的示例中有效,因为月份名称是小写的。使用单元测试来误导的有效演示。也许值得编辑以明确你的示例是一个边缘情况 :-) - David Clarke
这个很完美。我稍微改了一下函数,这样你就可以传递一个文化名称,因为我事先知道并且知道月份是什么语言。而且它可以是任何语言,任何时间。 - Niels Lucas

3
Public Function returnMonthNumber(ByVal monthName As String) As Integer
    Select Case monthName.ToLower
        Case Is = "january"
            Return 1
        Case Is = "february"
            Return 2
        Case Is = "march"
            Return 3
        Case Is = "april"
            Return 4
        Case Is = "may"
            Return 5
        Case Is = "june"
            Return 6
        Case Is = "july"
            Return 7
        Case Is = "august"
            Return 8
        Case Is = "september"
            Return 9
        Case Is = "october"
            Return 10
        Case Is = "november"
            Return 11
        Case Is = "december"
            Return 12
        Case Else
            Return 0
    End Select
End Function

警告代码处于Beta版本。


2
七年后回答这个问题,可以使用内置方法进行比较:
Month.toInt("January") > Month.toInt("May")

变成

Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
                 t => t.Equals("January", StringComparison.CurrentCultureIgnoreCase)) >
Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
                 t => t.Equals("May", StringComparison.CurrentCultureIgnoreCase))

这可以通过重构成扩展方法来简化。以下是一个LINQPad示例(因此调用Dump()方法):

void Main()
{
    ("January".GetMonthIndex() > "May".GetMonthIndex()).Dump();
    ("January".GetMonthIndex() == "january".GetMonthIndex()).Dump();
    ("January".GetMonthIndex() < "May".GetMonthIndex()).Dump();
}

public static class Extension {
    public static int GetMonthIndex(this string month) {
        return Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
                         t => t.Equals(month, StringComparison.CurrentCultureIgnoreCase));
    }
}

输出结果:

False
True
True

这是一个更好的解决方案,使用IgnoreCase字符串比较。这对于OP的问题很有效,但是如果您想使用此方法将其转换为与DateTime.Month返回的相同值,则建议将结果添加+1。当然,OP的比较要求仍然得到满足。 - iGanja

1

我将其翻译成西班牙语版本的C#代码,谢谢:

public string ObtenerNumeroMes(string NombreMes){

       string NumeroMes;   

       switch(NombreMes) {

        case ("ENERO") :
            NumeroMes = "01";
            return NumeroMes;

        case ("FEBRERO") :
            NumeroMes = "02";
            return NumeroMes;

        case ("MARZO") :
            NumeroMes = "03";
            return NumeroMes;

        case ("ABRIL") :
            NumeroMes = "04";
            return NumeroMes;

        case ("MAYO") :
            NumeroMes = "05";
            return NumeroMes;

        case ("JUNIO") :
            NumeroMes = "06";
            return NumeroMes;

        case ("JULIO") :
            NumeroMes = "07";
            return NumeroMes;

        case ("AGOSTO") :
            NumeroMes = "08";
            return NumeroMes;

        case ("SEPTIEMBRE") :
            NumeroMes = "09";
            return NumeroMes;

        case ("OCTUBRE") :
            NumeroMes = "10";
            return NumeroMes;

        case ("NOVIEMBRE") :
            NumeroMes = "11";
            return NumeroMes;

        case ("DICIEMBRE") :
            NumeroMes = "12";
            return NumeroMes;

            default:
            Console.WriteLine("Error");
            return "ERROR";

        }

   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接