Come posso convertire un numero intero in un nome di mese localizzato in Java?


99

Ottengo un numero intero e devo convertire in nomi di mese in varie lingue:

Esempio per locale en-us:
1 ->
2 gennaio -> febbraio

Esempio per locale es-mx:
1 -> Enero
2 -> Febrero


5
Attenzione, i mesi di Java sono a base zero quindi 0 = gen, 1 = feb, ecc.
Nick Holt,

hai ragione, quindi se hai bisogno di cambiare la lingua, devi solo cambiare la lingua. Grazie
atomsfat

2
@ NickHolt AGGIORNAMENTO L' enumerazione moderna java.timeMonthè basata su uno: 1-12 per gennaio-dicembre. Idem per [ 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` hanno schemi di numerazione pazzi. Uno dei tanti motivi per evitare le classi legacy, ora soppiantate interamente dalle classi java.time .
Basil Bourque

Risposte:


211
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}

12
Non è necessario "mese-1", poiché l'array è a base zero? atomsfat vuole 1 -> gennaio ecc.
Brian Agnew

7
Ha bisogno del mese 1, perché il mese è il numero del mese in base 1 che deve essere convertito nella posizione dell'array in base zero
Sam Barnum

5
public String getMonth (int month, Locale locale) {return DateFormatSymbols.getInstance (locale) .getMonths () [month-1]; }
atomsfat

4
Lui ha bisogno month-1. Chiunque altro utilizzi Calendar.get(Calendar.MONTH)avrà solo bisogno dimonth
Ron

1
L'implementazione di DateFormatSymbols è stata modificata in JDK 8, quindi il metodo getMonths non restituisce più i valori corretti per tutte le
impostazioni

33

È necessario utilizzare LLLL per i nomi dei mesi autonomi. questo è documentato nella SimpleDateFormatdocumentazione, come:

SimpleDateFormat dateFormat = new SimpleDateFormat( "LLLL", Locale.getDefault() );
dateFormat.format( date );

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

A partire da Java 1.8 (o 1.7 e 1.6 con ThreeTen-Backport ) puoi usare questo:

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

Nota che integerMonthè a base 1, ovvero 1 è per gennaio. L'intervallo è sempre da 1 a 12 per gennaio-dicembre (cioè solo calendario gregoriano).


diciamo che hai lo String Month of May in francese usando il metodo che hai postato (May in francese è Mai), come posso ottenere il numero 5 da questa String ??
usertest

@usertest Ho scritto una bozza di classe MonthDelocalizernella mia risposta per ottenere un Monthoggetto da una stringa del nome del mese localizzata passata: mai→ Month.MAY. Nota che la distinzione tra maiuscole e minuscole è importante: in francese, Mainon è valido e dovrebbe esserlo mai.
Basil Bourque

È il 2019. In che modo questa non è la risposta migliore?
nodo

16

Userei SimpleDateFormat. Qualcuno mi corregge se esiste un modo più semplice per creare un calendario mensile, lo faccio ora in codice e non ne sono così sicuro.

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

Queste terribili classi sono ora ereditate, soppiantate interamente dalle moderne classi java.time definite in JSR 310.
Basil Bourque

14

Ecco come lo farei. Lascio int montha te il controllo della portata .

import java.text.DateFormatSymbols;

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

12

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

Risultato: febbraio


7

Apparentemente in Android 2.2 c'è un bug con SimpleDateFormat.

Per poter utilizzare i nomi dei mesi devi definirli tu stesso nelle tue risorse:

<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 poi usali nel tuo codice in questo modo:

/**
 * 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;
}

"Apparentemente in Android 2.2 c'è un bug" - Sarebbe utile se potessi collegarti al punto in cui viene rintracciato il bug.
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

Molto più facile da fare ora nelle classi java.time che soppiantano queste vecchie e problematiche classi data-ora legacy.

L' Monthenum definisce una dozzina di oggetti, uno per ogni mese.

I mesi sono numerati da 1 a 12 per gennaio-dicembre.

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

Chiedere all'oggetto di generare una stringa del nome del mese, localizzata automaticamente .

Regola TextStyleper specificare la durata o l'abbreviazione del nome. Tieni presente che in alcune lingue (non in inglese) il nome del mese varia se usato da solo o come parte di una data completa. Quindi ogni stile di testo ha una …_STANDALONEvariante.

Specificare a Localeper determinare:

  • Quale lingua umana dovrebbe essere usata nella traduzione.
  • Quali norme culturali dovrebbero decidere questioni come l'abbreviazione, la punteggiatura e le maiuscole.

Esempio:

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

Nome → Monthoggetto

Cordiali saluti, andare nella direzione opposta (analizzare una stringa del nome del mese per ottenere un Monthoggetto enum) non è integrato. Potresti scrivere la tua classe per farlo. Ecco il mio rapido tentativo in una lezione del genere. Utilizzare a proprio rischio . Non ho pensato seriamente a questo codice né alcun test serio.

Utilizzo.

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

Codice.

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

Informazioni su java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantare la vecchia fastidiosi legacy classi data-time come java.util.Date, Calendar, e SimpleDateFormat.

Il progetto Joda-Time , ora in modalità di manutenzione , consiglia la migrazione alle classi java.time .

Per saperne di più, vedere il tutorial Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Puoi scambiare oggetti java.time direttamente con il tuo database. Utilizza un driver JDBC conforme a JDBC 4.2 o successivo. Non c'è bisogno di stringhe, non c'è bisogno di java.sql.*classi.

Dove ottenere le classi java.time?

  • Java SE 8 , Java SE 9 e versioni successive
    • Incorporato.
    • Parte dell'API Java standard con un'implementazione in bundle.
    • Java 9 aggiunge alcune funzionalità e correzioni minori.
  • Java SE 6 e Java SE 7
    • Gran parte delle funzionalità java.time sono portate indietro a Java 6 e 7 in ThreeTen-Backport .
  • Android
    • Versioni successive delle implementazioni di bundle Android delle classi java.time.
    • Per precedenza Android (<26), il ThreeTenABP progetto si adatta ThreeTen-Backport (di cui sopra). Vedi Come usare ThreeTenABP… .

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un banco di prova per possibili future aggiunte a java.time. Si possono trovare alcune classi utili, come per esempio Interval, YearWeek, YearQuartere altro .


1

C'è un problema quando si utilizza la classe DateFormatSymbols per il suo metodo getMonthName per ottenere Month by Name che mostra Month by Number in alcuni dispositivi Android. Ho risolto questo problema in questo modo:

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

Nella classe Java basta chiamare questo array in questo modo:

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

            }

Codifica felice :)


1

Estensione Kotlin

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

Utilizzo

calendar.get(Calendar.MONTH).toMonthName()

La Calendarclasse terribile è stata soppiantata anni fa dalle classi java.time definite in 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()));
}

questa sembra essere la risposta corretta, ma puoi spiegare cosa fai e perché lo fai in questo modo?
Martin Frank

Lo faccio in questo modo perché penso sia semplice e non complesso!
Diogo Oliveira

SimpleDateFormatTuttavia, utilizza la classe notoriamente fastidiosa e obsoleta .
Ole VV

Queste terribili classi data-ora sono state soppiantate anni fa dalle classi java.time definite in JSR 310.
Basil Bourque,


0

Prova a usarlo in un modo molto semplice e chiamalo come il tuo func

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

1
Non c'è bisogno di scrivere questo tipo di codice. Java è integrato Month::getDisplayName.
Basil Bourque

Non è necessario scrivere questo codice boilerplate. Controlla la mia risposta pubblicata sopra.
Sadda Hussain
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.