Bagaimana cara mengonversi Integer menjadi nama bulan yang dilokalkan di Java?

99

Saya mendapatkan integer dan saya perlu mengonversi menjadi nama bulan di berbagai lokal:

Contoh untuk locale en-us:
1 ->
2 Januari -> Februari

Contoh untuk lokal es-mx:
1 -> Enero
2 -> Febrero

atom lemak
sumber
5
Hati-hati, bulan-bulan di Jawa berbasis nol jadi 0 = Jan, 1 = Feb, dll
Nick Holt
Anda benar, jadi jika perlu mengubah bahasa, hanya perlu mengubah lokalnya. Terima kasih
atomsfat
2
@NickHolt UPDATEjava.timeMonth Enum modern berbasis satu: 1-12 untuk Januari-Desember. Ditto for [ 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` memiliki skema penomoran gila-gilaan. Salah satu dari banyak alasan untuk menghindari class lama, sekarang digantikan sepenuhnya oleh class java.time .
Basil Bourque

Jawaban:

211
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}
joe
sumber
12
Apakah Anda tidak memerlukan 'bulan-1', karena arraynya berbasis nol? atomsfat ingin 1 -> Januari dll.
Brian Agnew
7
Dia memang membutuhkan bulan ke-1, karena bulan adalah angka bulan berbasis 1 yang perlu dikonversi ke posisi array berbasis nol
Sam Barnum
5
public String getMonth (int bulan, Lokal lokal) {return DateFormatSymbols.getInstance (lokal) .getMonths () [bulan-1]; }
atom lemak
4
DIA membutuhkan month-1. Siapa pun yang menggunakan Calendar.get(Calendar.MONTH)hanya perlumonth
Ron
1
Implementasi DateFormatSymbols diubah di JDK 8, jadi metode getMonths tidak mengembalikan nilai yang benar untuk semua Lokal lagi: oracle.com/technetwork/java/javase/…
ahaaman
33

Anda perlu menggunakan LLLL untuk nama bulan yang berdiri sendiri. ini didokumentasikan dalam SimpleDateFormatdokumentasi, seperti:

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

Sejak Java 1.8 (atau 1.7 & 1.6 dengan ThreeTen-Backport ) Anda dapat menggunakan ini:

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

Perhatikan bahwa integerMonthini berbasis 1, yaitu 1 untuk Januari. Rentang selalu dari 1 hingga 12 untuk Januari-Desember (yaitu kalender Gregorian saja).

Oliv
sumber
katakanlah Anda memiliki String Bulan Mei dalam bahasa Prancis menggunakan metode yang Anda posting (Mei dalam bahasa Prancis adalah Mai), bagaimana saya bisa mendapatkan nomor 5 dari String ini ??
usertest
@usertest Saya menulis kelas draft kasar MonthDelocalizerdi Answer saya untuk mendapatkan Monthobjek dari string nama bulan yang dilokalkan: mai→ Month.MAY. Perhatikan bahwa sensitivitas huruf penting: Dalam bahasa Prancis, Maitidak valid dan seharusnya mai.
Basil Bourque
Ini tahun 2019. Bagaimana ini bukan jawaban teratas?
anothernode
16

Saya akan menggunakan SimpleDateFormat. Seseorang mengoreksi saya jika ada cara yang lebih mudah untuk membuat kalender bulanan, saya melakukan ini dalam kode sekarang dan saya tidak begitu yakin.

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
sumber
Kelas-kelas mengerikan ini sekarang sudah menjadi warisan, digantikan sepenuhnya oleh kelas-kelas java.time modern yang didefinisikan di JSR 310.
Basil Bourque
14

Begini cara saya melakukannya. Saya akan meninggalkan jangkauan memeriksa int monthterserah Anda.

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

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

Hasil: Februari

Terence
sumber
7

Ternyata di Android 2.2 ada bug dengan SimpleDateFormat.

Untuk menggunakan nama bulan, Anda harus menentukannya sendiri di sumber daya Anda:

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

Dan kemudian gunakan dalam kode Anda seperti ini:

/**
 * 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
sumber
"Rupanya di Android 2.2 ada bug" - Akan berguna jika Anda bisa menautkan ke tempat bug dilacak.
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

Jauh lebih mudah dilakukan sekarang di kelas java.time yang menggantikan kelas tanggal-waktu lama yang merepotkan ini.

The Monthenum mendefinisikan selusin benda, satu untuk setiap bulan.

Bulan-bulan tersebut diberi nomor 1-12 untuk Januari-Desember.

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

Minta objek untuk menghasilkan String nama bulan, secara otomatis dilokalkan .

Sesuaikan TextStyleuntuk menentukan berapa panjang atau singkatan nama yang Anda inginkan. Perhatikan bahwa dalam beberapa bahasa (bukan bahasa Inggris) nama bulan bervariasi jika digunakan sendiri atau sebagai bagian dari tanggal lengkap. Jadi, setiap gaya teks memiliki …_STANDALONEvarian.

Tentukan a Localeuntuk menentukan:

  • Bahasa manusia mana yang harus digunakan dalam terjemahan.
  • Norma budaya apa yang harus menentukan masalah seperti singkatan, tanda baca, dan penggunaan huruf besar.

Contoh:

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

Nama → Monthobjek

FYI, pergi ke arah lain (parsing string nama-bulan untuk mendapatkan Monthobjek enum) tidak built-in. Anda dapat menulis kelas Anda sendiri untuk melakukannya. Inilah upaya cepat saya di kelas seperti itu. Gunakan dengan resiko Anda sendiri . Saya tidak memberikan kode ini pemikiran serius atau pengujian serius.

Pemakaian.

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

Kode.

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

Tentang java.time

The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date, Calendar, & SimpleDateFormat.

Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time .

Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasinya adalah JSR 310 .

Anda dapat bertukar objek java.time langsung dengan database Anda. Gunakan driver JDBC yang sesuai dengan JDBC 4.2 atau yang lebih baru. Tidak perlu string, tidak perlu java.sql.*kelas.

Dimana mendapatkan kelas java.time?

Proyek ThreeTen-Extra memperluas java.time dengan kelas tambahan. Proyek ini adalah tempat pembuktian untuk kemungkinan penambahan java.time di masa mendatang. Anda mungkin menemukan beberapa kelas berguna di sini seperti Interval, YearWeek, YearQuarter, dan lebih .

Basil Bourque
sumber
1

Ada masalah saat Anda menggunakan kelas DateFormatSymbols untuk metode getMonthName untuk mendapatkan Bulan menurut Nama yang ditampilkan Bulan demi Nomor di beberapa perangkat Android. Saya telah menyelesaikan masalah ini dengan melakukan cara ini:

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

Di kelas Java, panggil saja array ini seperti ini:

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

            }

Selamat Coding :)

Faakhir
sumber
1

Ekstensi Kotlin

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

Pemakaian

calendar.get(Calendar.MONTH).toMonthName()
Sadda Hussain
sumber
Kelas mengerikan Calendartelah digantikan bertahun-tahun yang lalu oleh kelas java.time yang ditentukan di 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
sumber
sepertinya ini adalah jawaban yang tepat, tetapi dapatkah Anda menjelaskan apa yang Anda lakukan dan mengapa Anda melakukannya dengan cara ini?
Martin Frank
Saya melakukan cara ini karena menurut saya sederhana dan tidak rumit!
Diogo Oliveira
Ini menggunakan kelas yang terkenal merepotkan dan sudah lama ketinggalan zaman SimpleDateFormat.
Ole VV
Kelas tanggal-waktu yang mengerikan ini telah digantikan bertahun-tahun yang lalu oleh kelas java.time yang ditentukan di JSR 310.
Basil Bourque
0

Hanya memasukkan garis

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

akan melakukan triknya.

Kingsley Ijike
sumber
2
DateFormatSymbolsadalah bagian dari kelas tanggal-waktu mengerikan yang sekarang menjadi warisan, sejak adopsi JSR 310 . Sekarang digantikan oleh kelas java.time . Menyarankan penggunaannya pada 2019 adalah saran yang buruk.
Basil Bourque
Jawaban ini menduplikasi konten Jawaban yang diterima .
Basil Bourque
0

Cobalah untuk menggunakan ini dengan cara yang sangat sederhana dan menyebutnya sebagai func Anda sendiri

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
sumber
1
Tidak perlu menulis kode semacam ini. Java memiliki bawaan Month::getDisplayName.
Basil Bourque
Tidak perlu menulis kode boilerplate ini. Periksa jawaban saya yang diposting di atas.
Sadda Hussain