¿Cómo puedo convertir un entero a un nombre de mes localizado en Java?

99

Obtengo un número entero y necesito convertir los nombres de un mes en varias configuraciones regionales:

Ejemplo de configuración regional en-us:
1 ->
2 de enero -> febrero

Ejemplo de locale es-mx:
1 -> Enero
2 -> Febrero

átomos de grasa
fuente
5
Cuidado, los meses de Java se basan en cero, por lo que 0 = enero, 1 = febrero, etc.
Nick Holt
tiene razón, así que si necesita cambiar el idioma, solo necesita cambiar la configuración regional. Gracias
atomsfat
2
@NickHolt ACTUALIZACIÓN La java.timeMonthenumeración moderna se basa en uno: 1-12 para enero-diciembre. Lo mismo 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` tiene esquemas de numeración locos. Una de las muchas razones para evitar las clases heredadas, ahora reemplazadas por completo por las clases java.time .
Basil Bourque

Respuestas:

211
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}
Joe
fuente
12
¿No necesita 'mes-1', ya que la matriz se basa en cero? atomsfat quiere 1 -> enero, etc.
Brian Agnew
7
Necesita mes-1, porque el mes es el número de mes basado en 1 que debe convertirse a la posición de matriz de base cero
Sam Barnum
5
public String getMonth (int mes, Locale locale) {return DateFormatSymbols.getInstance (locale) .getMonths () [mes-1]; }
atomsfat
4
ÉL necesita month-1. Cualquier otra persona que use Calendar.get(Calendar.MONTH)solo necesitarámonth
Ron
1
La implementación de DateFormatSymbols se cambió en JDK 8, por lo que el método getMonths ya no devuelve los valores correctos para todas las configuraciones
ahaaman
33

Debe usar LLLL para nombres de meses independientes. esto está documentado en la SimpleDateFormatdocumentación, como:

SimpleDateFormat dateFormat = new SimpleDateFormat( "LLLL", Locale.getDefault() );
dateFormat.format( date );
Ilya Lisway
fuente
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 Java 1.8 (o 1.7 y 1.6 con ThreeTen-Backport ) puede usar esto:

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

Tenga en cuenta que integerMonthse basa en 1, es decir, 1 es para enero. El rango es siempre del 1 al 12 para enero-diciembre (es decir, solo en el calendario gregoriano).

Oliv
fuente
digamos que tienes el mes de las cuerdas de mayo en francés usando el método que publicaste (mayo en francés es Mai), ¿cómo puedo obtener el número 5 de esta cadena?
usertest
@usertest Escribí un borrador de clase MonthDelocalizeren mi Respuesta para obtener un Monthobjeto de una cadena de nombre de mes localizada pasada: mai→ Month.MAY. Tenga en cuenta que la distinción entre mayúsculas y minúsculas es importante: en francés, Maino es válido y debería serlo mai.
Basil Bourque
Es 2019. ¿Cómo no es esta la respuesta principal?
nodo
16

Usaría SimpleDateFormat. Alguien me corrija si hay una manera más fácil de hacer un calendario mensual, sin embargo, ahora hago esto en código y no estoy tan seguro.

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
fuente
Estas terribles clases ahora son heredadas, suplantadas por completo por las modernas clases java.time definidas en JSR 310.
Basil Bourque
14

Así es como lo haría yo. Dejaré que el rango revise int monthtu decisión.

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 el lagarto
fuente
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: febrero

Terence
fuente
7

Aparentemente, en Android 2.2 hay un error con SimpleDateFormat.

Para usar nombres de meses, debe definirlos usted mismo en sus 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>

Y luego úselos en su código de esta manera:

/**
 * 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
fuente
"Aparentemente en Android 2.2 hay un error" - Sería útil si pudieras vincular al lugar donde se rastrea el error.
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

Mucho más fácil de hacer ahora en las clases java.time que suplantan estas viejas y problemáticas clases de fecha y hora heredadas.

La Monthenumeración define una docena de objetos, uno para cada mes.

Los meses están numerados del 1 al 12 para enero-diciembre.

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

Pídale al objeto que genere una Cadena con el nombre del mes, localizado automáticamente .

Ajuste TextStylepara especificar cuánto tiempo o abreviado desea el nombre. Tenga en cuenta que en algunos idiomas (no en inglés) el nombre del mes varía si se usa solo o como parte de una fecha completa. Entonces, cada estilo de texto tiene una …_STANDALONEvariante.

Especifique a Localepara determinar:

  • Qué lenguaje humano debe usarse en la traducción.
  • Qué normas culturales deberían decidir cuestiones como la abreviatura, la puntuación y las mayúsculas.

Ejemplo:

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

Nombre → Month objeto

Para su información, ir en la otra dirección (analizar una cadena de nombre del mes para obtener un Monthobjeto enum) no está integrado. Podrías escribir tu propia clase para hacerlo. Aquí está mi rápido intento en tal clase. Úselo bajo su propio riesgo . No le di a este código ningún pensamiento serio ni ninguna prueba seria.

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

Acerca de java.time

El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como java.util.Date, Calendar, y SimpleDateFormat.

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No se necesitan cuerdas, no se necesitan java.sql.*clases.

¿Dónde obtener las clases java.time?

  • Java SE 8 , Java SE 9 y posterior
    • Incorporado.
    • Parte de la API estándar de Java con una implementación integrada.
    • Java 9 agrega algunas funciones y correcciones menores.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad de java.time está adaptada a Java 6 y 7 en ThreeTen-Backport .
  • Androide
    • Versiones posteriores de implementaciones de paquetes de Android de las clases java.time.
    • Para anteriormente Android (<26), el ThreeTenABP proyecto adapta ThreeTen-Backport (mencionado anteriormente). Consulte Cómo utilizar ThreeTenABP… .

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter, y más .

Albahaca Bourque
fuente
1

Hay un problema cuando usa la clase DateFormatSymbols para que su método getMonthName obtenga Month by Name y muestre Month by Number en algunos dispositivos Android. He resuelto este problema de esta manera:

En 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>

En la clase Java simplemente llame a esta matriz de esta manera:

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

            }

Codificación feliz :)

Faajir
fuente
1

Extensión de Kotlin

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

Uso

calendar.get(Calendar.MONTH).toMonthName()
Sadda Hussain
fuente
La Calendarclase terrible fue suplantada hace años por las clases java.time definidas en 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
fuente
esta parece ser la respuesta correcta, pero ¿puede explicar lo que hace y por qué lo hace de esta manera?
Martin Frank
¡Lo hago de esta manera porque creo que es simple y no complejo!
Diogo Oliveira
Sin SimpleDateFormatembargo, utiliza la clase notoriamente problemática y obsoleta .
Ole VV
Estas terribles clases de fecha y hora fueron suplantadas hace años por las clases java.time definidas en JSR 310.
Basil Bourque
0

Solo insertando la línea

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

hará el truco.

Kingsley Ijike
fuente
2
DateFormatSymbolses parte de las terribles clases de fecha y hora que ahora son heredadas, a partir de la adopción de JSR 310 . Ahora reemplazado por las clases java.time . Sugerir su uso en 2019 es un mal consejo.
Basil Bourque
Esta respuesta duplica el contenido de la respuesta aceptada .
Basil Bourque
0

Intenta usar esto de una manera muy simple y llámalo como tu propia función.

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
fuente
1
No es necesario escribir este tipo de código. Java tiene incorporado Month::getDisplayName.
Basil Bourque
No es necesario escribir este código repetitivo. Verifique mi respuesta publicada arriba.
Sadda Hussain