¿Cómo analizar el nombre de un mes (cadena) en un número entero para compararlo en C#?
Pregunta
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 manera es escribir su propio método, pero esto parece un problema bastante común que creo que ya se habría implementado en .Net. ¿Alguien ha hecho esto antes?
Solución
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.
Otros consejos
Podrías hacer algo como esto:
Convert.ToDate(month + " 01, 1900").Month
Si usas el DateTime.ParseExact()
-Método que varias personas han sugerido, ¡debes considerar cuidadosamente lo que quieres que suceda cuando la aplicación se ejecute en un entorno que no esté en inglés!
En Dinamarca, ¿cuál de ParseExact("Januar", ...)
y ParseExact("January", ...)
¿Debería funcionar y cuál debería fallar?
Esa será la diferencia entre CultureInfo.CurrentCulture
y CultureInfo.InvariantCulture
.
Puede usar el método DateTime.Parse para obtener un objeto DateTime y luego verificar su propiedad Month. Haga algo como esto:
int month = DateTime.Parse("1." + monthName + " 2008").Month;
El truco es construir una fecha válida para crear un objeto DateTime.
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 ().
No tiene que 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 cultura da-DK
, por lo que esta prueba de unidad 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 dejaré como un ejercicio para el lector para crear una sobrecarga en la que pueda pasar un CultureInfo explícito.
Una solución sencilla sería crear un Diccionario con nombres y valores. Luego, utilizando 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;
}
}
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
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
Si está utilizando c # 3.0 (o superior) puede usar extensores
Lo traduzco al código C # en la versión española, 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";
}
}
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 versión Beta.
Lo que hice fue usar SimpleDateFormat para crear una cadena de formato y analizar el texto a una fecha, y luego recuperar el mes a partir de eso. El código está debajo:
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();