Як проаналізувати ім'я місяця (рядок) на ціле число для порівняння в C #?


92

Мені потрібно мати можливість порівняти деякі назви місяців, які я маю в масиві.

Було б непогано, якби існував якийсь прямий спосіб, такий як:

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

Здається, мій пошук у Google пропонує єдиний спосіб написати свій власний метод, але це, здається, досить поширена проблема, і, на мою думку, вона вже була б реалізована в .Net, хтось робив це раніше?

Відповіді:


174

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

Хоча для ваших цілей вам, мабуть, буде краще просто створити Dictionary<string, int> зіставлення назви місяця з його значенням.


11
Обов’язково враховуйте stackoverflow.com/questions/258793/…, вирішуючи, чи використовувати CultureInfo.CurrentCulture або CultureInfo.InvariantCulture
Расмус Фабер


19

Якщо ви використовуєте DateTime.ParseExact()-метод, запропонований кількома людьми, вам слід ретельно продумати, що ви хочете, коли програма працює в неанглійському середовищі!

У Данії, який із ParseExact("Januar", ...)іParseExact("January", ...) повинен працювати, а хто - не?

Це буде різниця між CultureInfo.CurrentCultureі CultureInfo.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

Ви можете використовувати метод DateTime.Parse, щоб отримати об'єкт DateTime, а потім перевірити його властивість Month. Зробіть щось подібне:

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

Фокус полягає у побудові дійсної дати для створення об’єкта DateTime.


9

Ви можете використовувати перелік місяців:

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

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

Однак я не впевнений у синтаксисі enum.Parse () на 100%.


1
Це має бути "public Month ToInt (рядок введення) {...}", але в іншому випадку це правильно.
Джеймс Керран,

1
Я знаю, що це старий коментар, але я хотів би зазначити, що ви повинні починати перерахування з 1, наприклад, public enum Month { January = 1, Feburary }а також передати в int замість місяця.
eth0

@ eth0: Ой ... ти маєш рацію. Виправив, дякую, що вказав ;-)
Треб,

7

Для цього не потрібно створювати екземпляр 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()- я не знав, що одна з перевантажень перетворює рядок, using the casing rules of the specified cultureхоча, чесно кажучи, з назви методу не очевидно, що він може надати цю функціональність.
Девід Кларк

1
Гаразд, тому я тестував це за допомогою LINQPad, і я не можу змусити його працювати у своєму CurrentCulture. І "January".ToLower(CultureInfo.CurrentCulture).Dump();і "January".ToLower(new CultureInfo("en-NZ")).Dump();вихідні дані, januaryале імена місяців написані з великої літери в CurrentCulture.DateTimeFormat.MonthNames.
Девід Кларк

1
@DavidClarke Ну да, ви є викликом функції з ім'ям ToLower:) На насправді, є невеликий логічний вада в моєму коді, так як назви місяців будуть приведені в нижньому регістрі в так-DK. Отже, або не слід вводити малі літери, або ж слід також писати всі регістри назви місяців - залежно від того, чи бажаний збіг, який не враховує регістр, чи ні.
Марк Сіманн

1
Так, я інтерпретував документацію так, using the casing rules of the specified cultureщоб вона використовувала великі літери, наприклад, місяці та дні CultureInfo. Що працює у вашому прикладі, оскільки назви місяців є малими. Ефективна демонстрація використання одиничних тестів для введення в оману. Можливо, варто внести зміни, щоб зрозуміти, що ваш приклад - це кращий випадок :-)
Девід Кларк

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 # 3.0 (або вище), ви можете використовувати розширювачі


Тоді так, на жаль, я думаю, що ваш власний метод буде найелегантнішим рішенням.
Адам Нейлор

@AdamNaylor: що таке розширювачі? можете пояснити свою відповідь на прикладі?
Амір,

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

попереджувальний код у бета-версії.


Прийнята відповідь набагато краща.
James A Mohler

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

        }

   }

0

Що я зробив, це використовував SimpleDateFormat для створення рядка форматування та синтаксичного аналізу тексту до дати, а потім отримання місяця з цього. Код нижче:

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

0

Цей код допоможе вам ...

using System.Globalization;

....

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

Метод GetMonthName - повертає рядок ...

Якщо ви хочете отримати місяць як ціле число, тоді просто використовуйте -

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

Сподіваюся, це вам допоможе !!!

Дякую!!!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.