Comment puis-je convertir un entier en nom de mois localisé en Java?

99

J'obtiens un entier et je dois convertir en noms de mois dans divers paramètres régionaux:

Exemple pour locale en-us:
1 ->
2 janvier -> février

Exemple pour la locale es-mx:
1 -> Enero
2 -> Febrero

atomes gras
la source
5
Attention, les mois Java sont basés sur zéro, donc 0 = janvier, 1 = février, etc.
Nick Holt
vous avez raison, donc si vous avez besoin de changer de langue, il vous suffit de changer les paramètres régionaux. Merci
Atomfat
2
@NickHolt UPDATE L' java.timeMonthénumération moderne est basée sur un: 1-12 pour janvier-décembre. Idem pour [ 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` ont des schémas de numérotation fous. Une des nombreuses raisons d'éviter les anciennes classes, désormais entièrement supplantées par les classes java.time .
Basil Bourque

Réponses:

211
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}
Joe
la source
12
Vous n'avez pas besoin de «mois-1», puisque le tableau est basé sur zéro? atomfat veut 1 -> janvier etc.
Brian Agnew
7
Il a besoin du mois 1, car le mois est le numéro du mois basé sur 1 qui doit être converti en position de tableau de base zéro
Sam Barnum
5
public String getMonth (int month, Locale locale) {return DateFormatSymbols.getInstance (locale) .getMonths () [month-1]; }
atomfat
4
IL a besoin month-1. Quiconque utilise Calendar.get(Calendar.MONTH)aura juste besoinmonth
Ron
1
L'implémentation de DateFormatSymbols a été modifiée dans JDK 8, donc la méthode getMonths ne renvoie plus les valeurs correctes pour tous les paramètres
ahaaman
33

Vous devez utiliser LLLL pour les noms de mois autonomes. ceci est documenté dans la SimpleDateFormatdocumentation, tel que:

SimpleDateFormat dateFormat = new SimpleDateFormat( "LLLL", Locale.getDefault() );
dateFormat.format( date );
Ilya Lisway
la source
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

Depuis Java 1.8 (ou 1.7 et 1.6 avec le ThreeTen-Backport ), vous pouvez utiliser ceci:

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

Notez qu'il integerMonthest basé sur 1, c'est-à-dire que 1 correspond à janvier. La plage est toujours de 1 à 12 pour janvier-décembre (c.-à-d. Calendrier grégorien uniquement).

Oliv
la source
disons que vous avez le mois de mai en français en utilisant la méthode que vous avez postée (mai en français est Mai), comment puis-je obtenir le numéro 5 de cette chaîne ??
usertest
@usertest J'ai écrit un brouillon de classe MonthDelocalizerdans ma réponse pour obtenir un Monthobjet à partir d'une chaîne de nom de mois localisée passée: mai→ Month.MAY. Notez que le respect de la casse est important: en français, Main'est pas valide et devrait l'être mai.
Basil Bourque
Nous sommes en 2019. Comment n'est-ce pas la meilleure réponse?
anothernode
16

J'utiliserais SimpleDateFormat. Quelqu'un me corrige s'il existe un moyen plus simple de créer un calendrier mensuel, je le fais maintenant dans le code et je n'en suis pas si sûr.

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
la source
Ces classes terribles sont maintenant héritées, entièrement supplantées par les classes java.time modernes définies dans JSR 310.
Basil Bourque
14

Voici comment je le ferais. Je vous laisse le contrôle de la distance int month.

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 le lézard
la source
12

Utilisation de 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"); 

Résultat: février

Terence
la source
7

Apparemment, dans Android 2.2, il y a un bogue avec SimpleDateFormat.

Pour utiliser les noms de mois, vous devez les définir vous-même dans vos ressources:

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

Et puis utilisez-les dans votre code comme ceci:

/**
 * 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
la source
"Apparemment, dans Android 2.2, il y a un bogue" - Ce serait utile si vous pouviez créer un lien vers l'endroit où le bogue est suivi.
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

Beaucoup plus facile à faire maintenant dans les classes java.time qui remplacent ces anciennes classes de date-heure héritées.

L' Monthénumération définit une douzaine d'objets, un pour chaque mois.

Les mois sont numérotés de 1 à 12 pour janvier-décembre.

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

Demandez à l'objet de générer une chaîne du nom du mois, automatiquement localisée .

Ajustez le TextStylepour spécifier la longueur ou l'abréviation du nom. Notez que dans certaines langues (pas l'anglais), le nom du mois varie s'il est utilisé seul ou dans le cadre d'une date complète. Ainsi, chaque style de texte a une …_STANDALONEvariante.

Spécifiez un Localepour déterminer:

  • Quelle langue humaine doit être utilisée dans la traduction.
  • Quelles normes culturelles devraient décider des questions telles que l'abréviation, la ponctuation et la capitalisation.

Exemple:

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

Nom → Monthobjet

Pour info, aller dans l'autre sens (analyser une chaîne de nom du mois pour obtenir un Monthobjet enum) n'est pas intégré. Vous pouvez écrire votre propre classe pour le faire. Voici ma tentative rapide pour une telle classe. Utilisez à vos risques et périls . Je n'ai donné à ce code aucune pensée sérieuse ni aucun test sérieux.

Usage.

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

Code.

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

À propos de java.time

Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que java.util.Date, Calendar, et SimpleDateFormat.

Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .

Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .

Vous pouvez échanger des objets java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de chaînes, pas besoin de java.sql.*classes.

Où obtenir les classes java.time?

  • Java SE 8 , Java SE 9 et versions ultérieures
    • Intégré.
    • Partie de l'API Java standard avec une implémentation groupée.
    • Java 9 ajoute quelques fonctionnalités et corrections mineures.
  • Java SE 6 et Java SE 7
    • Une grande partie de la fonctionnalité java.time est rétroportée vers Java 6 et 7 dans ThreeTen-Backport .
  • Android
    • Versions ultérieures des implémentations de bundle Android des classes java.time.
    • Pour les versions antérieures d'Android (<26), le versionsprojetThreeTenABPadapteThreeTen-Backport(mentionné ci-dessus). Voir Comment utiliser ThreeTenABP… .

Le projet ThreeTen-Extra étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour d'éventuels futurs ajouts à java.time. Vous pouvez trouver ici quelques classes utiles telles que Interval,YearWeek , YearQuarteret plus .

Basil Bourque
la source
1

Il y a un problème lorsque vous utilisez la classe DateFormatSymbols pour sa méthode getMonthName pour obtenir Month by Name, il affiche Month by Number sur certains appareils Android. J'ai résolu ce problème en procédant de cette façon:

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

Dans la classe Java, appelez simplement ce tableau comme suit:

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

            }

Bon codage :)

Faakhir
la source
1

Extension Kotlin

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

Usage

calendar.get(Calendar.MONTH).toMonthName()
Sadda Hussain
la source
La Calendarclasse terrible a été supplantée il y a des années par les classes java.time définies dans 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
la source
cela semble être la bonne réponse, mais pouvez-vous expliquer ce que vous faites et pourquoi vous le faites de cette façon?
Martin Frank
Je fais de cette façon parce que je pense que c'est simple et pas complexe!
Diogo Oliveira
Il utilise cependant la SimpleDateFormatclasse notoirement gênante et dépassée depuis longtemps .
Ole VV
Ces terribles classes date-heure ont été supplantées il y a des années par les classes java.time définies dans JSR 310.
Basil Bourque
0

Insérez simplement la ligne

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

fera l'affaire.

Kingsley Ijike
la source
2
DateFormatSymbolsfait partie des terribles classes de date-heure qui sont maintenant héritées, depuis l'adoption de JSR 310 . Désormais supplanté par les classes java.time . Suggérer leur utilisation en 2019 est un mauvais conseil.
Basil Bourque
Cette réponse duplique le contenu de la réponse acceptée .
Basil Bourque
0

Essayez d'utiliser cela d'une manière très simple et appelez-le comme votre propre 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;
     }
Samer
la source
1
Pas besoin d'écrire ce genre de code. Java a intégré Month::getDisplayName.
Basil Bourque
Pas besoin d'écrire ce code standard. Vérifiez ma réponse ci-dessus.
Sadda Hussain