Wie kann ein Monatsname (Zeichenfolge) zum Vergleich in C # in eine Ganzzahl analysiert werden?

92

Ich muss in der Lage sein, einige Monatsnamen zu vergleichen, die ich in einem Array habe.

Es wäre schön, wenn es einen direkten Weg gäbe wie:

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

Meine Google-Suche scheint darauf hinzudeuten, dass die einzige Möglichkeit darin besteht, eine eigene Methode zu schreiben. Dies scheint jedoch ein häufig genug auftretendes Problem zu sein, von dem ich denke, dass es bereits in .Net implementiert wurde. Hat dies bereits jemand getan?

Spilliton
quelle

Antworten:

174

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

Obwohl Sie für Ihre Zwecke wahrscheinlich besser dran sind, nur eine Dictionary<string, int>Zuordnung des Monatsnamens zu seinem Wert zu erstellen .

James Curran
quelle
11
Berücksichtigen Sie unbedingt stackoverflow.com/questions/258793/…, wenn Sie entscheiden, ob Sie CultureInfo.CurrentCulture oder CultureInfo.InvariantCulture
Rasmus Faber
20

Sie könnten so etwas tun:

Convert.ToDate(month + " 01, 1900").Month
Aaron Palmer
quelle
19

Wenn Sie die von DateTime.ParseExact()mehreren Personen vorgeschlagene Methode verwenden, sollten Sie sorgfältig überlegen, was passieren soll, wenn die Anwendung in einer nicht englischen Umgebung ausgeführt wird!

Welches von ParseExact("Januar", ...)und ParseExact("January", ...)sollte in Dänemark funktionieren und welches sollte scheitern?

Das wird der Unterschied zwischen CultureInfo.CurrentCultureund sein CultureInfo.InvariantCulture.

Rasmus Faber
quelle
10

Eine einfache Lösung wäre, ein Wörterbuch mit Namen und Werten zu erstellen. Dann können Sie mit Contains () den richtigen Wert finden.

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;
    }
}
Carlos A. Ortiz
quelle
9

Sie können die DateTime.Parse-Methode verwenden, um ein DateTime-Objekt abzurufen und dann seine Month-Eigenschaft zu überprüfen. Mach so etwas:

int month = DateTime.Parse("1." + monthName + " 2008").Month;

Der Trick besteht darin, ein gültiges Datum zu erstellen, um ein DateTime-Objekt zu erstellen.

Rune Grimstad
quelle
9

Sie können eine Aufzählung von Monaten verwenden:

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

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

Ich bin mir jedoch nicht 100% sicher über die Syntax für enum.Parse ().

Treb
quelle
1
Es müsste "public Month ToInt (string Input) {...}" sein, aber sonst ist es korrekt.
James Curran
1
Ich weiß, dass dies ein alter Kommentar ist, dachte aber, ich würde darauf hinweisen, dass Sie Ihre Aufzählung mit 1 beginnen sollten, z. B. public enum Month { January = 1, Feburary }und statt eines Monats auch in ein int umwandeln sollten.
eth0
@ eth0: Ups ... du hast recht. Korrigiert, danke für den Hinweis
;-)
7

Sie müssen dazu keine DateTime-Instanz erstellen. So einfach ist das:

public static class Month
{
    public static int ToInt(this string month)
    {
        return Array.IndexOf(
            CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
            month.ToLower(CultureInfo.CurrentCulture))
            + 1;
    }
}

Ich beschäftige mich mit der da-DKKultur, daher besteht dieser Komponententest:

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

Ich überlasse es dem Leser als Übung, eine Überladung zu erstellen, in der Sie eine explizite CultureInfo übergeben können.

Mark Seemann
quelle
Gute Verwendung von ToLower()- Ich wusste nicht, dass eine der Überladungen die Zeichenfolge konvertiert, using the casing rules of the specified cultureobwohl es fairerweise aus dem Methodennamen nicht ersichtlich ist, dass sie diese Funktionalität bieten könnte.
David Clarke
1
Ok, ich habe dies mit LINQPad getestet und kann es in meinem nicht zum Laufen bringen CurrentCulture. Sowohl die Ausgabe- als auch die Monatsnamen werden in der Groß- "January".ToLower(CultureInfo.CurrentCulture).Dump();und "January".ToLower(new CultureInfo("en-NZ")).Dump();Kleinschreibung januarygroßgeschrieben CurrentCulture.DateTimeFormat.MonthNames.
David Clarke
1
@DavidClarke Nun ja, Sie werden den Aufruf einer Funktion namens ToLower:) Eigentlich gibt es eine leichte logische Fehler in meinem Code, seit Monatsnamen sind als Kleinbuchstaben in da-DK gegeben. Entweder sollte man die Eingabe nicht in Kleinbuchstaben schreiben, oder man sollte auch alle Monatsnamen in Kleinbuchstaben schreiben - je nachdem, ob eine Übereinstimmung ohne Berücksichtigung der Groß- und Kleinschreibung gewünscht wird oder nicht.
Mark Seemann
1
Ja, ich habe die Dokumentation so interpretiert using the casing rules of the specified culture, dass sie z. B. Monate und Tage pro Jahr kapitalisiert CultureInfo. Was in Ihrem Beispiel funktioniert, weil Monatsnamen in Kleinbuchstaben geschrieben sind. Effektive Demonstration der Verwendung von Unit-Tests zur Irreführung. Könnte eine Bearbeitung wert sein, um klar zu machen, dass Ihr Beispiel ein Randfall ist :-)
David Clarke
2

Wenn Sie diese Frage sieben Jahre nach der Beantwortung der Frage beantworten, können Sie diesen Vergleich mit integrierten Methoden durchführen:

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

wird

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

Was der Einfachheit halber in eine Erweiterungsmethode umgewandelt werden kann. Das Folgende ist ein LINQPad-Beispiel (daher die Dump()Methodenaufrufe):

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

Mit Ausgabe:

False
True
True
David Clarke
quelle
Dies ist eine viel bessere Lösung, wenn Sie den IgnoreCase-Zeichenfolgenvergleich verwenden. Dies funktioniert gut für die Frage des OP. Wenn Sie diese Methode jedoch zum Konvertieren in denselben von DateTime.Month zurückgegebenen Wert verwenden möchten, würde ich vorschlagen, dem Ergebnis +1 hinzuzufügen. Die Vergleichsanforderung des OP ist noch erfüllt oder natürlich.
iGanja
1

Wenn Sie c # 3.0 (oder höher) verwenden, können Sie Extender verwenden

Adam Naylor
quelle
Dann ja, leider denke ich, dass Ihre eigene Methode die eleganteste Lösung wäre.
Adam Naylor
@ AdamNaylor: Was sind Extender? Können Sie Ihre Antwort anhand eines Beispiels erklären?
Amir
1
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

Der Warncode ist in der Beta-Version.

Thabiso
quelle
Akzeptierte Antwort ist viel besser.
James A Mohler
1

Ich übersetze es in C # -Code in der spanischen Version, Grüße:

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

        }

   }
Maria Carolina Araujo
quelle
0

Ich habe SimpleDateFormat verwendet, um eine Formatzeichenfolge zu erstellen, den Text auf ein Datum zu analysieren und dann den Monat daraus abzurufen. Der Code ist unten:

int year = 2012 \\or any other year
String monthName = "January" \\or any other month
SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yyyy");
int monthNumber = format.parse("01-" + monthName + "-" + year).getMonth();
Ebenezer Ampiah
quelle
0

Dieser Code hilft Ihnen ...

using System.Globalization;

....

string FullMonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(DateTime.UtcNow.Month);

GetMonthName-Methode - gibt eine Zeichenfolge zurück ...

Wenn Sie einen Monat als Ganzzahl erhalten möchten, verwenden Sie einfach -

DateTime dt= DateTime.UtcNow;
int month= dt.Month;

Ich hoffe es hilft dir !!!

Vielen Dank!!!

Nitika Chopra
quelle