Como posso converter um número inteiro em nome de mês localizado em Java?

99

Recebo um número inteiro e preciso converter os nomes de um mês em vários locais:

Exemplo de localidade en-us:
1 ->
2 de janeiro -> fevereiro

Exemplo para localidade es-mx:
1 -> Enero
2 -> Febrero

gordura atômica
fonte
5
Cuidado, os meses do Java são baseados em zero, então 0 = janeiro, 1 = fevereiro, etc
Nick Holt
você está certo, portanto, se houver necessidade de alterar o idioma, basta alterar o local. Obrigado
atomsfat
2
@NickHolt ATUALIZAÇÃO O java.timeMonthenum moderno é baseado em um: 1-12 para janeiro-dezembro. Idem para [ java.time.DayOfWeek](https://docs.oracle.com/javase/9/docs/api/java/time/DayOfWeek.html): 1-7 for Monday-Sunday per ISO 8601 standard. Only the troublesome old legacy date-time classes such as Calendar` tem esquemas de numeração malucos. Uma das muitas razões para evitar as classes legadas, agora totalmente suplantadas pelas classes java.time .
Basil Bourque,

Respostas:

211
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}
joe
fonte
12
Você não precisa do 'mês 1', já que a matriz é baseada em zero? atomsfat quer 1 -> janeiro etc.
Brian Agnew
7
Ele precisa do mês 1, porque o mês é o número do mês baseado em 1 que precisa ser convertido para a posição da matriz baseada em zero
Sam Barnum
5
public String getMonth (int mês, localidade local) {return DateFormatSymbols.getInstance (localidade) .getMonths () [mês-1]; }
atomsfat
4
ELE precisa month-1. Qualquer outra pessoa que estiver usando Calendar.get(Calendar.MONTH)só precisarámonth
Ron
1
A implementação de DateFormatSymbols foi alterada no JDK 8, então o método getMonths não retorna mais os valores corretos para todos os Locale's: oracle.com/technetwork/java/javase/…
ahaaman
33

Você precisa usar LLLL para nomes de meses independentes. isso está documentado na SimpleDateFormatdocumentação, como:

SimpleDateFormat dateFormat = new SimpleDateFormat( "LLLL", Locale.getDefault() );
dateFormat.format( date );
Ilya Lisway
fonte
JDK 1.7 /IllegalArgumentException : Illegal pattern character 'L'
AntJavaDev
26

tl; dr

Month                             // Enum class, predefining and naming a dozen objects, one for each month of the year. 
.of( 12 )                         // Retrieving one of the enum objects by number, 1-12. 
.getDisplayName(
    TextStyle.FULL_STANDALONE , 
    Locale.CANADA_FRENCH          // Locale determines the human language and cultural norms used in localizing. 
)

java.time

Desde o Java 1.8 (ou 1.7 e 1.6 com o ThreeTen-Backport ), você pode usar isto:

Month.of(integerMonth).getDisplayName(TextStyle.FULL_STANDALONE, locale);

Observe que integerMonthé baseado em 1, ou seja, 1 é para janeiro. O intervalo é sempre de 1 a 12 para janeiro-dezembro (ou seja, apenas no calendário gregoriano).

Oliv
fonte
Digamos que você tenha o mês de maio da string em francês usando o método postado (maio em francês é mai), como posso obter o número 5 dessa string ??
usertest de
@usertest Eu escrevi uma classe de rascunho MonthDelocalizerem minha resposta para obter um Monthobjeto de uma string de nome de mês localizada passada: mai→ Mês.MAY. Observe que a distinção entre maiúsculas e minúsculas é importante: em francês, Maié inválido e deveria ser mai.
Basil Bourque,
Estamos em 2019. Como esta não é a melhor resposta?
anothernode
16

Eu usaria SimpleDateFormat. Alguém me corrija se houver uma maneira mais fácil de fazer um calendário mensal, eu faço isso em código agora e não tenho tanta certeza.

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;


public String formatMonth(int month, Locale locale) {
    DateFormat formatter = new SimpleDateFormat("MMMM", locale);
    GregorianCalendar calendar = new GregorianCalendar();
    calendar.set(Calendar.DAY_OF_MONTH, 1);
    calendar.set(Calendar.MONTH, month-1);
    return formatter.format(calendar.getTime());
}
Stevedbrown
fonte
Essas classes terríveis agora são legadas, suplantadas inteiramente pelas classes java.time modernas definidas em JSR 310.
Basil Bourque
14

É assim que eu faria. Vou deixar a verificação de alcance int monthpara você.

import java.text.DateFormatSymbols;

public String formatMonth(int month, Locale locale) {
    DateFormatSymbols symbols = new DateFormatSymbols(locale);
    String[] monthNames = symbols.getMonths();
    return monthNames[month - 1];
}
Bill the Lizard
fonte
12

Usando SimpleDateFormat.

import java.text.SimpleDateFormat;

public String formatMonth(String month) {
    SimpleDateFormat monthParse = new SimpleDateFormat("MM");
    SimpleDateFormat monthDisplay = new SimpleDateFormat("MMMM");
    return monthDisplay.format(monthParse.parse(month));
}


formatMonth("2"); 

Resultado: fevereiro

Terence
fonte
7

Aparentemente, no Android 2.2, há um bug com SimpleDateFormat.

Para usar nomes de meses, você mesmo deve defini-los em seus recursos:

<string-array name="month_names">
    <item>January</item>
    <item>February</item>
    <item>March</item>
    <item>April</item>
    <item>May</item>
    <item>June</item>
    <item>July</item>
    <item>August</item>
    <item>September</item>
    <item>October</item>
    <item>November</item>
    <item>December</item>
</string-array>

E, em seguida, use-os em seu código como este:

/**
 * Get the month name of a Date. e.g. January for the Date 2011-01-01
 * 
 * @param date
 * @return e.g. "January"
 */
public static String getMonthName(Context context, Date date) {

    /*
     * Android 2.2 has a bug in SimpleDateFormat. Can't use "MMMM" for
     * getting the Month name for the given Locale. Thus relying on own
     * values from string resources
     */

    String result = "";

    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    int month = cal.get(Calendar.MONTH);

    try {
        result = context.getResources().getStringArray(R.array.month_names)[month];
    } catch (ArrayIndexOutOfBoundsException e) {
        result = Integer.toString(month);
    }

    return result;
}
IHeartAndroid
fonte
"Aparentemente, no Android 2.2, há um bug" - seria útil se você pudesse criar um link para onde o bug é rastreado.
Peter Hall,
6

tl; dr

Month.of( yourMonthNumber )           // Represent a month by its number, 1-12 for January-December. 
  .getDisplayName(                    // Generate text of the name of the month automatically localized. 
      TextStyle.SHORT_STANDALONE ,    // Specify how long or abbreviated the name of month should be.
      new Locale( "es" , "MX" )       // Locale determines (a) the human language used in translation, and (b) the cultural norms used in deciding issues of abbreviation, capitalization, punctuation, and so on.
  )                                   // Returns a String.

java.time.Month

Muito mais fácil de fazer agora nas classes java.time que substituem essas antigas classes de data-hora antigas e problemáticas.

O Monthenum define uma dúzia de objetos, um para cada mês.

Os meses são numerados de 1 a 12 para janeiro a dezembro.

Month month = Month.of( 2 );  // 2 → February.

Peça ao objeto para gerar uma String com o nome do mês, localizada automaticamente .

Ajuste o TextStylepara especificar por quanto tempo ou abreviado deseja o nome. Observe que em alguns idiomas (exceto inglês) o nome do mês varia se usado sozinho ou como parte de uma data completa. Portanto, cada estilo de texto tem uma …_STANDALONEvariante.

Especifique um Localepara determinar:

  • Qual linguagem humana deve ser usada na tradução.
  • Quais normas culturais devem decidir questões como abreviatura, pontuação e capitalização.

Exemplo:

Locale l = new Locale( "es" , "MX" );
String output = Month.FEBRUARY.getDisplayName( TextStyle.SHORT_STANDALONE , l );  // Or Locale.US, Locale.CANADA_FRENCH. 

Nome → Monthobjeto

Para sua informação, ir na outra direção (analisar uma string de nome do mês para obter um Monthobjeto enum) não está embutido. Você pode escrever sua própria classe para fazer isso. Aqui está minha tentativa rápida de fazer tal classe. Use por sua conta e risco . Eu não dei a este código nenhuma reflexão séria nem qualquer teste sério.

Uso.

Month m = MonthDelocalizer.of( Locale.CANADA_FRENCH ).parse( "janvier" ) ;  // Month.JANUARY

Código.

package com.basilbourque.example;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.time.Month;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

// For a given name of month in some language, determine the matching `java.time.Month` enum object.
// This class is the opposite of `Month.getDisplayName` which generates a localized string for a given `Month` object.
// Usage… MonthDelocalizer.of( Locale.CANADA_FRENCH ).parse( "janvier" ) → Month.JANUARY
// Assumes `FormatStyle.FULL`, for names without abbreviation.
// About `java.time.Month` enum: https://docs.oracle.com/javase/9/docs/api/java/time/Month.html
// USE AT YOUR OWN RISK. Provided without guarantee or warranty. No serious testing or code review was performed.
public class MonthDelocalizer
{
    @NotNull
    private Locale locale;

    @NotNull
    private List < String > monthNames, monthNamesStandalone; // Some languages use an alternate spelling for a “standalone” month name used without the context of a date.

    // Constructor. Private, for static factory method.
    private MonthDelocalizer ( @NotNull Locale locale )
    {
        this.locale = locale;

        // Populate the pair of arrays, each having the translated month names.
        int countMonthsInYear = 12; // Twelve months in the year.
        this.monthNames = new ArrayList <>( countMonthsInYear );
        this.monthNamesStandalone = new ArrayList <>( countMonthsInYear );

        for ( int i = 1 ; i <= countMonthsInYear ; i++ )
        {
            this.monthNames.add( Month.of( i ).getDisplayName( TextStyle.FULL , this.locale ) );
            this.monthNamesStandalone.add( Month.of( i ).getDisplayName( TextStyle.FULL_STANDALONE , this.locale ) );
        }
//        System.out.println( this.monthNames );
//        System.out.println( this.monthNamesStandalone );
    }

    // Constructor. Private, for static factory method.
    // Personally, I think it unwise to default implicitly to a `Locale`. But I included this in case you disagree with me, and to follow the lead of the *java.time* classes. --Basil Bourque
    private MonthDelocalizer ( )
    {
        this( Locale.getDefault() );
    }

    // static factory method, instead of  constructors.
    // See article by Dr. Joshua Bloch. http://www.informit.com/articles/article.aspx?p=1216151
    // The `Locale` argument determines the human language and cultural norms used in de-localizing input strings.
    synchronized static public MonthDelocalizer of ( @NotNull Locale localeArg )
    {
        MonthDelocalizer x = new MonthDelocalizer( localeArg ); // This class could be optimized by caching this object.
        return x;
    }

    // Attempt to translate the name of a month to look-up a matching `Month` enum object.
    // Returns NULL if the passed String value is not found to be a valid name of month for the human language and cultural norms of the `Locale` specified when constructing this parent object, `MonthDelocalizer`.
    @Nullable
    public Month parse ( @NotNull String input )
    {
        int index = this.monthNames.indexOf( input );
        if ( - 1 == index )
        { // If no hit in the contextual names, try the standalone names.
            index = this.monthNamesStandalone.indexOf( input );
        }
        int ordinal = ( index + 1 );
        Month m = ( ordinal > 0 ) ? Month.of( ordinal ) : null;  // If we have a hit, determine the `Month` enum object. Else return null.
        if ( null == m )
        {
            throw new java.lang.IllegalArgumentException( "The passed month name: ‘" + input + "’ is not valid for locale: " + this.locale.toString() );
        }
        return m;
    }

    // `Object` class overrides.

    @Override
    public boolean equals ( Object o )
    {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;

        MonthDelocalizer that = ( MonthDelocalizer ) o;

        return locale.equals( that.locale );
    }

    @Override
    public int hashCode ( )
    {
        return locale.hashCode();
    }

    public static void main ( String[] args )
    {
        // Usage example:
        MonthDelocalizer monthDelocJapan = MonthDelocalizer.of( Locale.JAPAN );
        try
        {
            Month m = monthDelocJapan.parse( "pink elephant" ); // Invalid input.
        } catch ( IllegalArgumentException e )
        {
            // … handle error
            System.out.println( "ERROR: " + e.getLocalizedMessage() );
        }

        // Ignore exception. (not recommended)
        if ( MonthDelocalizer.of( Locale.CANADA_FRENCH ).parse( "janvier" ).equals( Month.JANUARY ) )
        {
            System.out.println( "GOOD - In locale "+Locale.CANADA_FRENCH+", the input ‘janvier’ parses to Month.JANUARY." );
        }
    }
}

Sobre java.time

A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como java.util.Date, Calendar, e SimpleDateFormat.

O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .

Para saber mais, consulte o tutorial Oracle . E pesquise no Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Você pode trocar objetos java.time diretamente com seu banco de dados. Use um driver JDBC compatível com JDBC 4.2 ou posterior. Não há necessidade de cordas, não há necessidade de java.sql.*classes.

Onde obter as classes java.time?

  • Java SE 8 , Java SE 9 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação agrupada.
    • Java 9 adiciona alguns recursos e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores de implementações de pacotes Android das classes java.time.
    • Para anteriormente Android (<26), o ThreeTenABP projeto adapta ThreeTen-Backport (mencionados acima). Consulte Como usar o ThreeTenABP… .

O projeto ThreeTen-Extra estende java.time com classes adicionais. Este projeto é um campo de provas para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como Interval, YearWeek, YearQuarter, e mais .

Basil Bourque
fonte
1

Há um problema quando você usa a classe DateFormatSymbols para seu método getMonthName para obter Mês por Nome para mostrar Mês por Número em alguns dispositivos Android. Resolvi esse problema fazendo desta forma:

Em String_array.xml

<string-array name="year_month_name">
    <item>January</item>
    <item>February</item>
    <item>March</item>
    <item>April</item>
    <item>May</item>
    <item>June</item>
    <item>July</item>
    <item>August</item>
    <item>September</item>
    <item>October</item>
    <item>November</item>
    <item>December</item>
    </string-array>

Na classe Java, apenas chame este array desta maneira:

public String[] getYearMonthName() {
        return getResources().getStringArray(R.array.year_month_names);
        //or like 
       //return cntx.getResources().getStringArray(R.array.month_names);
    } 

      String[] months = getYearMonthName(); 
           if (i < months.length) {
            monthShow.setMonthName(months[i] + " " + year);

            }

Happy Coding :)

Faakhir
fonte
1

Extensão Kotlin

fun Int.toMonthName(): String {
    return DateFormatSymbols().months[this]
}

Uso

calendar.get(Calendar.MONTH).toMonthName()
Sadda Hussain
fonte
A Calendarclasse terrível foi suplantada anos atrás pelas classes java.time definidas em JSR 310.
Basil Bourque
0
    public static void main(String[] args) {
    SimpleDateFormat format = new SimpleDateFormat("MMMMM", new Locale("en", "US"));
    System.out.println(format.format(new Date()));
}
Diogo Oliveira
fonte
essa parece ser a resposta adequada, mas você pode explicar o que faz e por que faz assim?
Martin Frank
Faço assim porque acho simples e não complexo!
Diogo Oliveira
SimpleDateFormatPorém, ele usa a classe notoriamente problemática e há muito desatualizada .
Ole VV de
Essas classes terríveis de data e hora foram suplantadas anos atrás pelas classes java.time definidas em JSR 310.
Basil Bourque
0

Basta inserir a linha

DateFormatSymbols.getInstance().getMonths()[view.getMonth()] 

vai fazer o truque.

Kingsley Ijike
fonte
2
DateFormatSymbolsfaz parte das terríveis classes de data e hora que agora são legadas, a partir da adoção da JSR 310 . Agora suplantado pelas classes java.time . Sugerir seu uso em 2019 é um conselho ruim.
Basil Bourque
Esta Resposta duplica o conteúdo da Resposta aceita .
Basil Bourque
0

Tente usar isso de uma forma muito simples e chame-o como se fosse sua função

public static String convertnumtocharmonths(int m){
         String charname=null;
         if(m==1){
             charname="Jan";
         }
         if(m==2){
             charname="Fev";
         }
         if(m==3){
             charname="Mar";
         }
         if(m==4){
             charname="Avr";
         }
         if(m==5){
             charname="Mai";
         }
         if(m==6){
             charname="Jun";
         }
         if(m==7){
             charname="Jul";
         }
         if(m==8){
             charname="Aou";
         }
         if(m==9){
             charname="Sep";
         }
         if(m==10){
             charname="Oct";
         }
         if(m==11){
             charname="Nov";
         }
         if(m==12){
             charname="Dec";
         }
         return charname;
     }
Samer
fonte
1
Não há necessidade de escrever esse tipo de código. Java foi integrado Month::getDisplayName.
Basil Bourque de
Não há necessidade de escrever este código clichê. Verifique minha resposta postada acima.
Sadda Hussain