¿Cómo analizar el nombre de un mes (cadena) en un número entero para compararlo en C #?


92

Necesito poder comparar algunos nombres de meses que tengo en una matriz.

Sería bueno si hubiera alguna forma directa como:

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

Mi búsqueda en Google parece sugerir que la única forma es escribir su propio método, pero esto parece un problema lo suficientemente común como para pensar que ya se habría implementado en .Net, ¿alguien ha hecho esto antes?

Respuestas:


174

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

Aunque, para sus propósitos, probablemente sea mejor crear una Dictionary<string, int>asignación del nombre del mes a su valor.


11
Asegúrese de considerar stackoverflow.com/questions/258793/… al decidir si usar CultureInfo.CurrentCulture o CultureInfo.InvariantCulture
Rasmus Faber

20

Podrías hacer algo como esto:

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

19

Si usa el DateTime.ParseExact()método -que varias personas han sugerido, debe considerar cuidadosamente lo que desea que suceda cuando la aplicación se ejecute en un entorno que no sea inglés.

En Dinamarca, que de ParseExact("Januar", ...)y ParseExact("January", ...)debe trabajar y que deben fallar?

Esa será la diferencia entre CultureInfo.CurrentCulturey CultureInfo.InvariantCulture.


10

Una solución sencilla sería crear un diccionario con nombres y valores. Luego, usando Contains () puede encontrar el valor correcto.

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

Puede usar el método DateTime.Parse para obtener un objeto DateTime y luego verificar su propiedad Month. Haz algo como esto:

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

El truco consiste en crear una fecha válida para crear un objeto DateTime.


9

Puede usar una enumeración de meses:

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

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

Sin embargo, no estoy 100% seguro de la sintaxis de enum.Parse ().


1
Debería ser "Public Month ToInt (string Input) {...}" pero por lo demás es correcto.
James Curran

1
Sé que este es un comentario antiguo, pero pensé en señalar que debería comenzar su enumeración desde 1, por ejemplo, public enum Month { January = 1, Feburary }y también convertir a un int en lugar de Month.
eth0

@ eth0: Vaya ... tienes razón. Corregido, gracias por señalarlo ;-)
Treb

7

No es necesario crear una instancia de DateTime para hacer esto. Es tan simple como esto:

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

Me estoy ejecutando en la da-DKcultura, por lo que esta prueba unitaria pasa:

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

Lo dejo como ejercicio para que el lector cree una sobrecarga donde pueda pasar una CultureInfo explícita.


Buen uso de ToLower(): no sabía que una de las sobrecargas convierte la cadena, using the casing rules of the specified cultureaunque para ser justos, no es obvio por el nombre del método que pueda ofrecer esa funcionalidad.
David Clarke

1
Ok, he estado probando esto usando LINQPad y no puedo hacer que funcione en mi CurrentCulture. Tanto "January".ToLower(CultureInfo.CurrentCulture).Dump();y "January".ToLower(new CultureInfo("en-NZ")).Dump();de salida januarynombres pero el mes se capitalizan en el CurrentCulture.DateTimeFormat.MonthNames.
David Clarke

1
@DavidClarke Bueno, sí, que están llamando a una función llamada ToLower:) En realidad, hay un ligero error lógico en mi código, ya que los nombres del mes se dan como todo en minúsculas en da-DK. Por lo tanto, no se debe poner en minúscula la entrada, o también se deben minúsculas todos los nombres de los meses, dependiendo de si se desea o no una coincidencia que no distinga entre mayúsculas y minúsculas.
Mark Seemann

1
Sí, estaba interpretando la documentación using the casing rules of the specified cultureen el sentido de que se capitalizaría, por ejemplo, meses y días por CultureInfo. Lo que funciona en su ejemplo porque los nombres de los meses están en minúsculas. Demostración eficaz del uso de pruebas unitarias para inducir a error. Podría ser digno de una edición para dejar en claro que su ejemplo es un caso límite :-)
David Clarke

2

Y respondiendo esto siete años después de que se hizo la pregunta, es posible hacer esta comparación utilizando métodos integrados:

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

se convierte en

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

Que se puede refactorizar en un método de extensión para simplificar. El siguiente es un ejemplo de LINQPad (de ahí las Dump()llamadas al método):

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

Con salida:

False
True
True

Esta es una solución mucho mejor usando la comparación de cadenas IgnoreCase. Esto funciona bien para la pregunta del OP, sin embargo, si desea utilizar este método para convertir al mismo valor devuelto por DateTime.Month, sugeriría agregar +1 al resultado. Por supuesto, el requisito de comparación del OP aún se cumple.
iGanja

1

Si está usando c # 3.0 (o superior) puede usar extensores


Entonces sí, lamentablemente creo que su propio método sería la solución más elegante.
Adam Naylor

@AdamNaylor: ¿que son los extensores? ¿Puede explicar su respuesta con un ejemplo?
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

El código de precaución está en la versión Beta.


La respuesta aceptada es mucho mejor.
James A Mohler

1

Lo traduzco al código C # en la versión en español, saludos:

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

Lo que hice fue usar SimpleDateFormat para crear una cadena de formato, analizar el texto a una fecha y luego recuperar el mes de eso. El código está abajo:

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

Este código te ayuda ...

using System.Globalization;

....

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

Método GetMonthName: devuelve una cadena ...

Si desea obtener un mes como un número entero, simplemente use -

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

¡¡¡Espero que te ayude!!!

¡¡¡Gracias!!!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.