Como analisar um nome mês (string) para um inteiro para comparação em C #?
Pergunta
Eu preciso ser capaz de comparar alguns nomes de meses que eu tenho em uma matriz.
Seria bom se houvesse alguma maneira direta como:
Month.toInt("January") > Month.toInt("May")
My Google pesquisa parece sugerir a única maneira é escrever seu próprio método, mas este parece ser um problema bastante comum que eu acho que já teria sido implementado em .Net, ninguém fez isso antes?
Solução
DateTime.ParseExact(monthName, "MMMM", CultureInfo.CurrentCulture ).Month
Embora, para suas finalidades, você provavelmente vai ser melhor fora apenas a criação de um Dictionary<string, int>
mapeando o nome do mês para o seu valor.
Outras dicas
Você poderia fazer algo parecido com isto:
Convert.ToDate(month + " 01, 1900").Month
Se você usar o DateTime.ParseExact()
-método que várias pessoas têm sugerido, você deve considerar cuidadosamente o que você quer que aconteça quando o aplicativo é executado em um ambiente não-Inglês!
Na Dinamarca, o que ParseExact("Januar", ...)
e ParseExact("January", ...)
deve trabalhar e que deve falhar?
Essa será a diferença entre CultureInfo.CurrentCulture
e CultureInfo.InvariantCulture
.
Você pode usar o método DateTime.Parse para obter um objeto DateTime e, em seguida, verificar a sua propriedade mês. Fazer algo como isto:
int month = DateTime.Parse("1." + monthName + " 2008").Month;
O truque é construir uma data válida para criar um objeto DateTime.
Você pode usar uma enumeração de meses:
public enum Month
{
January,
February,
// (...)
December,
}
public Month ToInt(Month Input)
{
return (int)Enum.Parse(typeof(Month), Input, true));
}
Não estou 100% certo sobre a sintaxe para Enum.Parse (), no entanto.
Você não tem que criar uma instância de DateTime para fazer isso. É tão simples como isto:
public static class Month
{
public static int ToInt(this string month)
{
return Array.IndexOf(
CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
month.ToLower(CultureInfo.CurrentCulture))
+ 1;
}
}
Estou correndo na cultura da-DK
, de modo que este teste de unidade passa:
[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);
}
Vou deixar isso como um exercício para o leitor a criar uma sobrecarga onde você pode passar um CultureInfo explícito.
Uma solução simples seria criar um dicionário com nomes e valores. Em seguida, usando Contém () você pode encontrar o valor correto.
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;
}
}
E responder a esta sete anos após a pergunta foi feita, é possível fazer esta comparação usando built-in métodos:
Month.toInt("January") > Month.toInt("May")
se torna
Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
t => t.Equals("January", StringComparison.CurrentCultureIgnoreCase)) >
Array.FindIndex( CultureInfo.CurrentCulture.DateTimeFormat.MonthNames,
t => t.Equals("May", StringComparison.CurrentCultureIgnoreCase))
O que pode ser reformulado em um método de extensão para simplificar. O seguinte é um exemplo LINQPad (daí as chamadas de método 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));
}
}
Com saída:
False
True
True
Se você estiver usando c # 3.0 (ou superior) você pode usar extensores
Eu traduzi-lo em código C # na versão em espanhol, diz respeito:
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
código de cautela é a versão Beta.
O que eu fiz foi usar SimpleDateFormat para criar uma seqüência de formato, e analisar o texto para uma data, e depois recuperar o mês a partir daí. O código está abaixo:
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();