Làm thế nào để phân tích cú pháp tên tháng (chuỗi) thành một số nguyên để so sánh trong C #?


92

Tôi cần có thể so sánh một số tên tháng mà tôi có trong một mảng.

Sẽ rất tuyệt nếu có một số cách trực tiếp như:

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

Tìm kiếm trên Google của tôi dường như đề xuất cách duy nhất là viết phương pháp của riêng bạn, nhưng đây có vẻ như là một vấn đề đủ phổ biến mà tôi nghĩ rằng nó đã được triển khai trong .Net, có ai đã làm điều này trước đây không?

Câu trả lời:


174

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

Mặc dù đối với mục đích của bạn, tốt hơn hết bạn nên tạo một Dictionary<string, int>ánh xạ tên của tháng với giá trị của nó.


11
Hãy chắc chắn xem xét stackoverflow.com/questions/258793/… khi quyết định sử dụng CultureInfo.CurrentCulture hay CultureInfo.InvariantCulture
Rasmus Faber

20

Bạn có thể làm điều gì đó như sau:

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

19

Nếu bạn sử dụng DateTime.ParseExact()-method mà một số người đã đề xuất, bạn nên cân nhắc cẩn thận những gì bạn muốn xảy ra khi ứng dụng chạy trong môi trường không phải tiếng Anh!

Ở Đan Mạch, trong đó ParseExact("Januar", ...)ParseExact("January", ...)nên làm việc và đó nên thất bại?

Đó sẽ là sự khác biệt giữa CultureInfo.CurrentCultureCultureInfo.InvariantCulture.


10

Một giải pháp đơn giản là tạo Từ điển với tên và giá trị. Sau đó, sử dụng Contains (), bạn có thể tìm thấy giá trị phù hợp.

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

Bạn có thể sử dụng phương thức DateTime.Parse để lấy một đối tượng DateTime và sau đó kiểm tra thuộc tính Tháng của nó. Làm điều gì đó như sau:

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

Bí quyết là xây dựng một ngày hợp lệ để tạo một đối tượng DateTime.


9

Bạn có thể sử dụng enum của tháng:

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

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

Tuy nhiên, tôi không chắc chắn 100% về cú pháp của enum.Parse ().


1
Nó sẽ cần phải là "Tháng công khai ToInt (string Input) {...}" nhưng nếu không thì nó đúng.
James Curran

1
Tôi biết đây là một nhận xét cũ nhưng tôi nghĩ rằng bạn nên bắt đầu enum của mình từ 1, ví dụ: public enum Month { January = 1, Feburary }và cũng được chuyển thành int thay vì Month.
eth0

@ eth0: Rất tiếc ... bạn nói đúng. Đã sửa nó, cảm ơn vì đã chỉ ra nó ;-)
Treb

7

Bạn không cần phải tạo một phiên bản DateTime để thực hiện việc này. Nó đơn giản như sau:

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

Tôi đang chạy trên da-DKvăn hóa, vì vậy bài kiểm tra đơn vị này vượt qua:

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

Tôi sẽ để nó như một bài tập cho người đọc để tạo ra quá tải nơi bạn có thể chuyển vào một CultureInfo rõ ràng.


Sử dụng tốt ToLower()- Tôi không biết một trong những quá tải chuyển đổi chuỗi using the casing rules of the specified culturemặc dù công bằng mà nói, nó không rõ ràng từ tên phương thức rằng nó có thể có chức năng đó.
David Clarke

1
Ok, vì vậy tôi đã thử nghiệm điều này bằng LINQPad và tôi không thể làm cho nó hoạt động trong của tôi CurrentCulture. Cả hai "January".ToLower(CultureInfo.CurrentCulture).Dump();"January".ToLower(new CultureInfo("en-NZ")).Dump();đầu ra januarynhưng tên tháng được viết hoa trong CurrentCulture.DateTimeFormat.MonthNames.
David Clarke

1
@DavidClarke Vâng, vâng, bạn đang gọi một hàm có tên là ToLower:) Thực ra, có một lỗ hổng logic nhỏ trong mã của tôi, vì tên tháng được đặt dưới dạng tất cả các chữ thường trong da-DK. Vì vậy, một trong hai không nên viết thường đầu vào, hoặc nếu không thì cũng phải viết thường tất cả các tên tháng - tùy thuộc vào việc có mong muốn kết hợp không phân biệt chữ hoa chữ thường hay không.
Mark Seemann

1
Có Tôi đang giải thích tài liệu using the casing rules of the specified culturecó nghĩa là nó sẽ viết hoa, ví dụ như tháng và ngày trên mỗi CultureInfo. Điều này hoạt động trong ví dụ của bạn vì tên tháng là chữ thường. Chứng minh hiệu quả của việc sử dụng các bài kiểm tra đơn vị để đánh lừa. Có thể xứng đáng với một chỉnh sửa để làm cho nó rõ ràng rằng ví dụ của bạn là một trường hợp cạnh :-)
David Clarke

2

Và trả lời câu hỏi này bảy năm sau khi câu hỏi được đặt ra, có thể thực hiện so sánh này bằng cách sử dụng các phương pháp tích hợp:

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

trở thành

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

Có thể cấu trúc lại thành một phương thức mở rộng cho đơn giản. Sau đây là một ví dụ về LINQPad (do đó Dump()phương thức gọi):

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

Với đầu ra:

False
True
True

Đây là một giải pháp tốt hơn nhiều khi sử dụng so sánh chuỗi Bỏ qua. Điều này hoạt động tốt cho câu hỏi của OP, tuy nhiên nếu bạn muốn sử dụng phương pháp này để chuyển đổi sang cùng một giá trị được trả về bởi DateTime.Month, tôi khuyên bạn nên thêm +1 vào kết quả. Yêu cầu so sánh của OP vẫn được đáp ứng hoặc tất nhiên.
iGanja

1

Nếu bạn đang sử dụng c # 3.0 (hoặc cao hơn), bạn có thể sử dụng bộ mở rộng


Sau đó, vâng, rất tiếc, tôi nghĩ rằng phương pháp của riêng bạn sẽ là giải pháp thanh lịch nhất.
Adam Naylor

@AdamNaylor: bộ mở rộng là gì? bạn có thể giải thích câu trả lời của bạn với một ví dụ?
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

mã thận trọng ở phiên bản Beta.


Câu trả lời được chấp nhận là tốt hơn nhiều.
James A Mohler 7/12/12

1

Tôi dịch nó sang mã C # trong phiên bản tiếng Tây Ban Nha, liên quan đến:

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

Những gì tôi đã làm là sử dụng SimpleDateFormat để tạo một chuỗi định dạng và phân tích cú pháp văn bản thành một ngày, sau đó truy xuất tháng từ đó. Mã dưới đây:

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

Mã này giúp bạn ...

using System.Globalization;

....

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

Phương thức GetMonthName - nó trả về chuỗi ...

Nếu bạn muốn lấy một tháng dưới dạng số nguyên, thì chỉ cần sử dụng:

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

Tôi hy vọng nó sẽ giúp bạn!!!

Cảm ơn!!!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.