Làm cách nào để chuyển đổi Số nguyên thành tên tháng được bản địa hóa trong Java?


99

Tôi nhận được một số nguyên và tôi cần chuyển đổi sang tên tháng ở các ngôn ngữ khác nhau:

Ví dụ cho ngôn ngữ en-us:
1 ->
2 tháng 1 -> tháng 2

Ví dụ cho ngôn ngữ es-mx:
1 -> Enero
2 -> Febrero


5
Hãy chú ý, các tháng của Java không dựa trên số 0 nên 0 = tháng 1, 1 = tháng 2, v.v.
Nick Holt

bạn đúng, vì vậy nếu cần thay đổi ngôn ngữ, chỉ cần thay đổi ngôn ngữ. Cảm ơn
atomsfat

2
@NickHolt CẬP NHẬTjava.timeMonth Enum hiện đại dựa trên một nền tảng: 1-12 cho tháng 1-12. Ditto cho [ 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 Lịch` có các kế hoạch đánh số điên rồ. Một trong nhiều lý do để tránh các lớp kế thừa, hiện được thay thế hoàn toàn bởi các lớp java.time .
Basil Bourque vào

Câu trả lời:


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

12
Bạn không cần 'month-1', vì mảng là số 0? atomsfat muốn 1 -> Tháng Một, vv
Brian Agnew

7
Ông không cần tháng 1, bởi vì tháng là số tháng 1 dựa trên mà cần phải được chuyển đổi sang vị trí mảng zero-based
Sam Barnum

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

4
NGÀI cần month-1. Bất cứ ai khác sử dụng Calendar.get(Calendar.MONTH)sẽ chỉ cầnmonth
Ron

1
DateFormatSymbols thực hiện được thay đổi trong JDK 8, vì vậy phương pháp getMonths không trả lại giá trị đúng cho tất cả của Locale nữa: oracle.com/technetwork/java/javase/...
ahaaman

33

Bạn cần sử dụng LLLL cho các tên tháng độc lập. điều này được ghi lại trong SimpleDateFormattài liệu, chẳng hạn như:

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

JDK 1.7 /IllegalArgumentException : Illegal pattern character 'L'
AntJavaDev 29/09/17

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

Kể từ Java 1.8 (hoặc 1.7 & 1.6 với ThreeTen-Backport ), bạn có thể sử dụng cái này:

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

Lưu ý rằng integerMonthdựa trên 1, tức là 1 dành cho tháng Giêng. Phạm vi luôn từ 1 đến 12 cho tháng 1 đến tháng 12 (tức là chỉ theo lịch Gregory).


giả sử bạn có Chuỗi tháng của tháng 5 trong tiếng Pháp bằng cách sử dụng phương pháp bạn đã đăng (Tháng 5 trong tiếng Pháp là Mai), làm thế nào tôi có thể lấy số 5 từ Chuỗi này ??
tốt nhất

@usertest Tôi đã viết một lớp nháp MonthDelocalizertrong Câu trả lời của mình để lấy một Monthđối tượng từ chuỗi tên tháng được bản địa hóa đã chuyển: mai→ Month.MAY. Lưu ý rằng vấn đề phân biệt chữ hoa chữ thường: Trong tiếng Pháp, Maikhông hợp lệ và nên như vậy mai.
Basil Bourque vào

Đó là năm 2019. Làm thế nào đây không phải là câu trả lời hàng đầu?
othernode 19/09/19

16

Tôi sẽ sử dụng SimpleDateFormat. Ai đó sửa cho tôi nếu có cách nào dễ dàng hơn để tạo lịch được chỉnh sửa, tôi làm điều này bằng mã ngay bây giờ và tôi không chắc lắm.

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

Những lớp học khủng khiếp đang di sản, thay thế hoàn toàn bằng các hiện đại java.time lớp được định nghĩa trong JSR 310.
Basil Bourque

14

Đây là cách tôi sẽ làm điều đó. Tôi sẽ để lại phạm vi kiểm tra int monthtùy thuộc vào bạn.

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

Sử dụng 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"); 

Kết quả: Tháng 2


7

Rõ ràng trong Android 2.2 có một lỗi với SimpleDateFormat.

Để sử dụng tên tháng, bạn phải tự xác định chúng trong tài nguyên của mình:

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

Và sau đó sử dụng chúng trong mã của bạn như sau:

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

"Rõ ràng là trong Android 2.2 có một lỗi" - Sẽ rất hữu ích nếu bạn có thể liên kết đến nơi lỗi được theo dõi.
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

Giờ đây, việc thực hiện dễ dàng hơn nhiều trong các lớp java.time thay thế các lớp ngày-giờ kế thừa cũ rắc rối này.

Các Monthenum định nghĩa một chục đối tượng, một cho mỗi tháng.

Các tháng được đánh số từ 1-12 cho tháng 1-12.

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

Yêu cầu đối tượng tạo Chuỗi tên của tháng, được bản địa hóa tự động .

Điều chỉnh TextStyleđể chỉ định độ dài hoặc viết tắt bạn muốn tên. Lưu ý rằng trong một số ngôn ngữ (không phải tiếng Anh), tên tháng sẽ thay đổi nếu được sử dụng một mình hoặc như một phần của ngày hoàn chỉnh. Vì vậy, mỗi kiểu văn bản có một …_STANDALONEbiến thể.

Chỉ định a Localeđể xác định:

  • Ngôn ngữ của con người nên được sử dụng trong dịch thuật.
  • Các chuẩn mực văn hóa nào sẽ quyết định các vấn đề như viết tắt, dấu câu và viết hoa.

Thí dụ:

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

Tên → Monthđối tượng

FYI, đi theo hướng khác (phân tích cú pháp chuỗi tên tháng để lấy một Monthđối tượng enum) không được tích hợp sẵn. Bạn có thể viết lớp của riêng bạn để làm như vậy. Đây là nỗ lực nhanh chóng của tôi trong một lớp học như vậy. Sử dụng có rủi ro của riêng bạn . Tôi đã đưa ra mã này không có suy nghĩ nghiêm túc cũng như bất kỳ thử nghiệm nghiêm túc nào.

Sử dụng.

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

Mã.

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

Giới thiệu về java.time

Các java.time khung được xây dựng vào Java 8 và sau đó. Những lớp học thay thế cái cũ phiền hà di sản lớp học ngày thời gian như java.util.Date, Calendar, & SimpleDateFormat.

Các Joda thời gian dự án, bây giờ trong chế độ bảo trì , khuyên chuyển đổi sang các java.time lớp.

Để tìm hiểu thêm, hãy xem Hướng dẫn Oracle . Và tìm kiếm Stack Overflow để có nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310 .

Bạn có thể trao đổi các đối tượng java.time trực tiếp với cơ sở dữ liệu của mình. Sử dụng trình điều khiển JDBC tương thích với JDBC 4.2 trở lên. Không cần chuỗi, không cần java.sql.*lớp.

Lấy các lớp java.time ở đâu?

  • Java SE 8 , Java SE 9 và mới hơn
    • Được xây dựng trong.
    • Một phần của API Java tiêu chuẩn với triển khai theo gói.
    • Java 9 bổ sung một số tính năng nhỏ và các bản sửa lỗi.
  • Java SE 6 Java SE 7
    • Phần lớn chức năng của java.time được chuyển ngược sang Java 6 & 7 trong ThreeTen-Backport .
  • Android
    • Các phiên bản triển khai gói Android mới hơn của các lớp java.time.
    • Đối với Android trước đó (<26), các ThreeTenABP dự án thích nghi ThreeTen-backport (nêu trên). Xem Cách sử dụng ThreeTenABP… .

Các ThreeTen-Extra dự án mở rộng java.time với các lớp bổ sung. Dự án này là cơ sở chứng minh cho những bổ sung có thể có trong tương lai cho java.time. Bạn có thể tìm thấy một số các lớp học hữu ích ở đây chẳng hạn như Interval, YearWeek, YearQuarter, và nhiều hơn nữa .


1

Đã xảy ra sự cố khi bạn sử dụng lớp DateFormatSymbols cho phương thức getMonthName của nó để lấy Tháng theo Tên. Nó hiển thị Tháng theo Số trong một số thiết bị Android. Tôi đã giải quyết vấn đề này bằng cách làm theo cách này:

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

Trong lớp Java chỉ cần gọi mảng này như sau:

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

            }

Mã hóa vui vẻ :)


1

Phần mở rộng Kotlin

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

Sử dụng

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

Khủng khiếp Calendarlớp được thay thế năm trước bởi các java.time lớp được định nghĩa trong 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()));
}

đây có vẻ là câu trả lời thích hợp, nhưng bạn có thể giải thích bạn làm gì và tại sao bạn làm theo cách này không?
Martin Frank

Tôi làm theo cách này vì tôi nghĩ là đơn giản và không phức tạp!
Diogo Oliveira

Tuy nhiên, nó sử dụng lớp nổi tiếng rắc rối và đã lỗi thời SimpleDateFormat.
Ole VV

Những lớp học ngày-thời gian khủng khiếp đã được thay thế năm trước bởi các java.time lớp được định nghĩa trong JSR 310.
Basil Bourque

0

Chỉ cần chèn dòng

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

sẽ thực hiện thủ thuật.


2
DateFormatSymbolslà một phần của các lớp ngày-thời gian khủng khiếp mà bây giờ là di sản, kể từ khi áp dụng JSR 310 . Bây giờ được thay thế bởi các lớp java.time . Đề xuất sử dụng chúng vào năm 2019 là lời khuyên tồi.
Basil Bourque

Câu trả lời này sao chép nội dung của Câu trả lời được chấp nhận .
Basil Bourque

0

Cố gắng sử dụng nó một cách rất đơn giản và gọi nó giống như func của riêng bạn

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
Không cần phải viết loại mã này. Java được tích hợp sẵn Month::getDisplayName.
Basil Bourque

Không cần phải viết đoạn mã soạn sẵn này. Kiểm tra câu trả lời của tôi được đăng ở trên.
Sadda Hussain
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.