Wie kann ich eine Ganzzahl in einen lokalisierten Monatsnamen in Java konvertieren?

99

Ich erhalte eine Ganzzahl und muss an verschiedenen Orten in einen Monatsnamen konvertieren:

Beispiel für das Gebietsschema en-us:
1 ->
2. Januar -> Februar

Beispiel für das Gebietsschema es-mx:
1 -> Enero
2 -> Febrero

Atomfett
quelle
5
Achtung, Java-Monate basieren auf Null, also 0 = Jan, 1 = Feb usw.
Nick Holt
Sie haben Recht. Wenn Sie also die Sprache ändern müssen, müssen Sie nur das Gebietsschema ändern. Danke
Atomefat
2
@NickHolt UPDATE Die moderne java.timeMonthAufzählung basiert auf einem: 1-12 für Januar-Dezember. Das Gleiche gilt für [ 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 Kalender` haben verrückte Nummerierungsschemata. Einer der vielen Gründe, die Legacy-Klassen zu vermeiden, die jetzt vollständig durch die java.time- Klassen ersetzt werden.
Basil Bourque

Antworten:

212
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}
Joe
quelle
12
Benötigen Sie nicht 'Monat-1', da das Array auf Null basiert? Atomsfat will 1 -> Januar etc.
Brian Agnew
7
Er braucht Monat-1, weil der Monat die 1-basierte Monatszahl ist, die in die nullbasierte Array-Position konvertiert werden muss
Sam Barnum
5
public String getMonth (int month, Locale locale) {return DateFormatSymbols.getInstance (locale) .getMonths () [month-1]; }
Atomfett
4
ER braucht month-1. Jeder andere, der es benutzt Calendar.get(Calendar.MONTH), braucht nurmonth
Ron
1
Die Implementierung von DateFormatSymbols wurde in JDK 8 geändert, sodass die Methode getMonths nicht mehr für alle Gebietsschemas die richtigen Werte zurückgibt
ahaaman
33

Sie müssen LLLL für eigenständige Monatsnamen verwenden. Dies ist in der SimpleDateFormatDokumentation dokumentiert, z.

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

Seit Java 1.8 (oder 1.7 & 1.6 mit dem ThreeTen-Backport ) können Sie Folgendes verwenden:

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

Beachten Sie, dass integerMonth1-basiert ist, dh 1 ist für Januar. Der Bereich reicht von Januar bis Dezember immer von 1 bis 12 (dh nur Gregorianischer Kalender).

Oliv
quelle
Nehmen wir an, Sie haben den String-Monat Mai auf Französisch mit der von Ihnen angegebenen Methode (Mai auf Französisch ist Mai). Wie kann ich die Nummer 5 aus diesem String erhalten?
Usertest
@usertest Ich habe MonthDelocalizerin meiner Antwort eine Rohentwurfsklasse geschrieben , um ein MonthObjekt aus einer übergebenen lokalisierten Monatsnamenzeichenfolge maiabzurufen : → Month.MAY. Beachten Sie, dass die Groß- und Kleinschreibung wichtig ist: Auf Französisch Maiist ungültig und sollte es sein mai.
Basil Bourque
Es ist 2019. Wie ist das nicht die beste Antwort?
Anothernode
16

Ich würde SimpleDateFormat verwenden. Jemand korrigiert mich, wenn es einen einfacheren Weg gibt, einen Monatskalender zu erstellen. Ich mache das jetzt im Code und bin mir nicht so sicher.

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());
}
Strohbraun
quelle
Diese schrecklichen Klassen sind jetzt Vermächtnis, vollständig ersetzt durch die modernen Java.time- Klassen, die in JSR 310 definiert sind.
Basil Bourque
14

So würde ich es machen. Ich überlasse es Ihnen, die Reichweite zu überprüfen 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 die Eidechse
quelle
12

Verwenden von 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"); 

Ergebnis: Februar

Terence
quelle
7

Anscheinend gibt es in Android 2.2 einen Fehler mit SimpleDateFormat.

Um Monatsnamen verwenden zu können, müssen Sie diese in Ihren Ressourcen selbst definieren:

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

Und verwenden Sie sie dann wie folgt in Ihrem Code:

/**
 * 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
quelle
"Anscheinend gibt es in Android 2.2 einen Fehler" - Es wäre nützlich, wenn Sie einen Link zu dem Ort erstellen könnten, an dem der Fehler verfolgt wird.
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

In den java.time-Klassen, die diese problematischen alten Legacy-Datums- und Uhrzeitklassen ersetzen, ist dies jetzt viel einfacher.

Die MonthAufzählung definiert ein Dutzend Objekte, eines für jeden Monat.

Die Monate sind von Januar bis Dezember mit 1-12 nummeriert.

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

Bitten Sie das Objekt, eine Zeichenfolge mit dem Namen des Monats zu generieren , die automatisch lokalisiert wird .

Passen Sie das TextStylean, um anzugeben, wie lange oder abgekürzt der Name sein soll. Beachten Sie, dass in einigen Sprachen (nicht Englisch) der Monatsname variiert, wenn er alleine oder als Teil eines vollständigen Datums verwendet wird. Jeder Textstil hat also eine …_STANDALONEVariante.

Geben Sie a Localean, um Folgendes zu bestimmen:

  • Welche menschliche Sprache sollte bei der Übersetzung verwendet werden?
  • Welche kulturellen Normen sollten über Themen wie Abkürzung, Zeichensetzung und Großschreibung entscheiden?

Beispiel:

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

Name → MonthObjekt

Zu Ihrer Information: Wenn Sie in die andere Richtung gehen (eine Zeichenfolge mit dem Namen des Monats analysieren, um ein MonthEnum-Objekt zu erhalten), ist dies nicht integriert. Sie könnten dazu Ihre eigene Klasse schreiben. Hier ist mein kurzer Versuch in einer solchen Klasse. Benutzung auf eigene Gefahr . Ich habe diesen Code weder ernsthaft überlegt noch ernsthaft getestet.

Verwendung.

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

Über java.time

Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie java.util.Date, Calendar, & SimpleDateFormat.

Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .

Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .

Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für java.sql.*Klassen.

Woher bekomme ich die java.time-Klassen?

Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden Interval, YearWeek, YearQuarter, und mehr .

Basil Bourque
quelle
1

Es gibt ein Problem, wenn Sie die DateFormatSymbols-Klasse für ihre getMonthName-Methode verwenden, um Monat für Name abzurufen. Auf einigen Android-Geräten wird Monat für Nummer angezeigt. Ich habe dieses Problem folgendermaßen gelöst:

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>

Rufen Sie in der Java-Klasse dieses Array einfach folgendermaßen auf:

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

            }

Viel Spaß beim Codieren :)

Faakhir
quelle
1

Kotlin-Erweiterung

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

Verwendung

calendar.get(Calendar.MONTH).toMonthName()
Sadda Hussain
quelle
Die schreckliche CalendarKlasse wurde vor Jahren durch die in JSR 310 definierten Java.time- Klassen ersetzt.
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
quelle
Das scheint die richtige Antwort zu sein, aber können Sie erklären, was Sie tun und warum Sie es so machen?
Martin Frank
Ich mache das so, weil ich denke, es ist einfach und nicht komplex!
Diogo Oliveira
Es verwendet jedoch die notorisch mühsame und längst veraltete SimpleDateFormatKlasse.
Ole VV
Diese schrecklichen Datums- und Uhrzeitklassen wurden vor Jahren durch die in JSR 310 definierten Java.time- Klassen ersetzt.
Basil Bourque
0

Einfach die Zeile einfügen

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

wird den Trick machen.

Kingsley Ijike
quelle
2
DateFormatSymbolsist Teil der schrecklichen Datums- und Uhrzeitklassen, die seit der Einführung von JSR 310 Legacy sind . Jetzt ersetzt durch die java.time- Klassen. Die Verwendung im Jahr 2019 vorzuschlagen, ist ein schlechter Rat.
Basil Bourque
Diese Antwort dupliziert den Inhalt der akzeptierten Antwort .
Basil Bourque
0

Versuchen Sie dies auf sehr einfache Weise zu verwenden und nennen Sie es wie Ihre eigene Funktion

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
quelle
1
Sie müssen diese Art von Code nicht schreiben. Java hat eingebaut Month::getDisplayName.
Basil Bourque
Sie müssen diesen Code nicht schreiben. Überprüfen Sie meine Antwort oben.
Sadda Hussain