Jak przekonwertować liczbę całkowitą na zlokalizowaną nazwę miesiąca w Javie?

99

Otrzymuję liczbę całkowitą i muszę przekonwertować na nazwy miesięcy w różnych lokalizacjach:

Przykład dla języka en-us:
1 -> January
2 -> luty

Przykład dla języka es-mx:
1 -> Enero
2 -> Febrero

atomsfat
źródło
5
Uważaj, miesiące Java są liczone od zera, więc 0 = styczeń, 1 = luty itd.
Nick Holt,
masz rację, więc jeśli trzeba zmienić język, wystarczy zmienić ustawienia regionalne. Dzięki
atomsfat
2
@NickHolt UPDATE Nowoczesne java.timeMonthwyliczenie jest oparte na jedynkach : 1-12 dla stycznia-grudnia. Podobnie jak w przypadku [ 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 Kalendarza] istnieją szalone schematy numeracji. Jeden z wielu powodów, dla których należy unikać klas starszych, obecnie całkowicie wypieranych przez klasy java.time .
Basil Bourque,

Odpowiedzi:

211
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}
joe
źródło
12
Czy nie potrzebujesz „miesiąca-1”, ponieważ tablica jest liczona od zera? atomsfat chce 1 -> stycznia itd.
Brian Agnew
7
Potrzebuje miesiąca-1, ponieważ miesiąc jest liczbą miesiąca liczoną od 1, którą należy przekonwertować na pozycję tablicy od zera
Sam Barnum
5
public String getMonth (int miesiąc, locale locale) {return DateFormatSymbols.getInstance (locale) .getMonths () [month-1]; }
atomsfat
4
ON potrzebuje month-1. Każdy inny Calendar.get(Calendar.MONTH)będzie potrzebowałmonth
Ron
1
Implementacja DateFormatSymbols została zmieniona w JDK 8, więc metoda getMonths nie zwraca już poprawnych wartości dla wszystkich
ustawień
33

Musisz używać LLLL dla samodzielnych nazw miesięcy. jest to udokumentowane w SimpleDateFormatdokumentacji, takiej jak:

SimpleDateFormat dateFormat = new SimpleDateFormat( "LLLL", Locale.getDefault() );
dateFormat.format( date );
Ilya Lisway
źródło
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

Od Java 1.8 (lub 1.7 i 1.6 z ThreeTen-Backport ) możesz używać tego:

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

Zauważ, że integerMonthjest oparty na 1, czyli 1 oznacza styczeń. Zakres obejmuje zawsze od 1 do 12 w okresie styczeń-grudzień (tj. Tylko kalendarz gregoriański).

Oliv
źródło
powiedzmy, że masz miesiąc majowy String po francusku, używając metody, którą opublikowałeś (maj po francusku to Mai), jak mogę uzyskać liczbę 5 z tego ciągu?
test użytkownika
@usertest Napisałem wstępną klasę MonthDelocalizerw mojej odpowiedzi, aby pobrać Monthobiekt z przekazanego zlokalizowanego ciągu nazwy miesiąca: mai→ Month.MAY. Pamiętaj, że rozróżnianie wielkości liter ma znaczenie: w języku francuskim Maijest nieważne i powinno mai.
Basil Bourque,
Jest rok 2019. Dlaczego to nie jest najlepsza odpowiedź?
anothernode
16

Użyłbym SimpleDateFormat. Ktoś poprawi mnie, jeśli istnieje łatwiejszy sposób na zrobienie miesięcznego kalendarza, robię to teraz w kodzie i nie jestem taki pewien.

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
źródło
Te okropne klasy są teraz spuścizną, całkowicie wypartą przez nowoczesne klasy java.time zdefiniowane w JSR 310.
Basil Bourque
14

Oto jak bym to zrobił. Zostawię sprawdzanie zakresu od int monthciebie.

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
źródło
12

Korzystanie z 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"); 

Wynik: luty

Terence
źródło
7

Najwyraźniej w Androidzie 2.2 jest błąd w SimpleDateFormat.

Aby używać nazw miesięcy, musisz zdefiniować je samodzielnie w swoich zasobach:

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

Następnie użyj ich w swoim kodzie w następujący sposób:

/**
 * 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
źródło
„Najwyraźniej w Androidzie 2.2 jest błąd” - Przydałoby się, gdybyś udostępnił link do miejsca śledzenia błędu.
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

Dużo łatwiej jest teraz zrobić w klasach java.time, które zastępują te kłopotliwe, starsze klasy data-czas.

MonthEnum określa kilkanaście obiektów, po jednym dla każdego miesiąca.

Miesiące od stycznia do grudnia są ponumerowane od 1 do 12.

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

Poproś obiekt o wygenerowanie ciągu z nazwą miesiąca, automatycznie zlokalizowanego .

Dostosuj, TextStyleaby określić, jak długa lub skrócona ma być nazwa. Należy pamiętać, że w niektórych językach (nie w języku angielskim) nazwa miesiąca różni się, jeśli jest używana samodzielnie lub jako część pełnej daty. Dlatego każdy styl tekstu ma inny …_STANDALONEwariant.

Określ a, Localeaby określić:

  • Jakiego języka ludzkiego użyć w tłumaczeniu.
  • Jakie normy kulturowe powinny decydować o kwestiach, takich jak skróty, interpunkcja i wielkie litery.

Przykład:

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

Nazwa → Monthobiekt

FYI, pójście w innym kierunku (analiza ciągu z nazwą miesiąca w celu uzyskania Monthobiektu wyliczenia) nie jest wbudowane. Możesz w tym celu napisać własną klasę. Oto moja szybka próba takiej klasy. Używaj na własne ryzyko . Nie zastanawiałem się nad tym kodem ani nie poddawałem go poważnym testom.

Stosowanie.

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

Kod.

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

Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*klas.

Skąd wziąć klasy java.time?

  • Java SE 8 , Java SE 9 i nowsze
    • Wbudowany.
    • Część standardowego interfejsu API języka Java z dołączoną implementacją.
    • Java 9 dodaje kilka drobnych funkcji i poprawek.
  • Java SE 6 i Java SE 7
    • Wiele funkcji java.time jest przenoszonych z powrotem do Java 6 i 7 w ThreeTen-Backport .
  • Android
    • Późniejsze wersje implementacji klas java.time w pakietach Androida.
    • Dla wcześniejszej Androida (<26), ThreeTenABP projekt dostosowuje ThreeTen-backportu (jak wyżej). Zobacz Jak używać ThreeTenABP… .

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
1

Występuje problem podczas używania klasy DateFormatSymbols dla metody getMonthName w celu pobrania miesiąca według nazwy, która pokazuje miesiąc według numeru na niektórych urządzeniach z systemem Android. Rozwiązałem ten problem w ten sposób:

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

W klasie Java po prostu wywołaj tę tablicę w następujący sposób:

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

            }

Miłego kodowania :)

Faakhir
źródło
1

Rozszerzenie Kotlin

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

Stosowanie

calendar.get(Calendar.MONTH).toMonthName()
Sadda Hussain
źródło
Straszliwa Calendarklasa została wyparta laty przez java.time klas zdefiniowanych w 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
źródło
wygląda na to, że to właściwa odpowiedź, ale czy możesz wyjaśnić, co robisz i dlaczego robisz to w ten sposób?
Martin Frank,
Robię w ten sposób, ponieważ uważam, że jest to proste i niezłożone!
Diogo Oliveira
Używa jednak notorycznie kłopotliwej i dawno przestarzałej SimpleDateFormatklasy.
Ole VV
Te okropne klasy daty i czasu zostały wyparte lata temu przez klasy java.time zdefiniowane w JSR 310.
Basil Bourque
0

Po prostu wstawiam linię

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

da rade.

Kingsley Ijike
źródło
2
DateFormatSymbolsjest częścią okropnych klas daty i czasu, które są teraz starsze, od przyjęcia JSR 310 . Teraz zastąpione przez klasy java.time . Sugerowanie ich użycia w 2019 roku to kiepska rada.
Basil Bourque
Ta odpowiedź powiela treść zaakceptowanej odpowiedzi .
Basil Bourque
0

Spróbuj użyć tego w bardzo prosty sposób i nazwij to jak własną funkcją

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
źródło
1
Nie ma potrzeby pisania tego rodzaju kodu. Java ma wbudowany Month::getDisplayName.
Basil Bourque
Nie ma potrzeby pisania tego standardowego kodu. Sprawdź moją odpowiedź zamieszczoną powyżej.
Sadda Hussain