Как я могу преобразовать целое число в локализованное название месяца в Java?

99

Я получаю целое число, и мне нужно преобразовать в названия месяцев в разных языках:

Пример для locale en-us:
1 ->
2 января -> февраль

Пример для locale es-mx:
1 -> Enero
2 -> Febrero

атомжир
источник
5
Осторожно, месяцы Java отсчитываются от нуля, поэтому 0 = январь, 1 = февраль и т. Д.
Ник Холт,
Вы правы, поэтому, если нужно сменить язык, просто нужно сменить локаль. Спасибо
atomfat
2
@NickHolt ОБНОВЛЕНИЕ Современное java.timeMonthперечисление основано на единице: 1-12 для января-декабря. То же самое для [ 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` имеет сумасшедшие схемы нумерации. Одна из многих причин избегать устаревших классов, которые теперь полностью вытеснены классами java.time .
Basil Bourque

Ответы:

213
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}
Джо
источник
12
Вам не нужен «месяц-1», поскольку массив отсчитывается от нуля? atomfat хочет 1 -> января и т. д.
Брайан Агнью,
7
Ему действительно нужен месяц-1, потому что месяц - это номер месяца с отсчетом от 1, который необходимо преобразовать в позицию массива с
отсчетом
5
общедоступная строка getMonth (int месяц, языковой стандарт) {return DateFormatSymbols.getInstance (locale) .getMonths () [месяц-1]; }
atomfat
4
ОН нуждается month-1. Кто-нибудь еще, использующий, Calendar.get(Calendar.MONTH)будет просто нуждатьсяmonth
Рон
1
Реализация DateFormatSymbols была изменена в JDK 8, поэтому метод getMonths больше не возвращает правильные значения для всех Locale: oracle.com/technetwork/java/javase/…
ahaaman
33

Вам необходимо использовать LLLL для автономных названий месяцев. это задокументировано в SimpleDateFormatдокументации, например:

SimpleDateFormat dateFormat = new SimpleDateFormat( "LLLL", Locale.getDefault() );
dateFormat.format( date );
Илья Лисуэй
источник
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

Начиная с Java 1.8 (или 1.7 и 1.6 с ThreeTen-Backport ) вы можете использовать это:

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

Обратите внимание, что integerMonthотсчитывается от 1, т.е. 1 соответствует январю. Диапазон всегда от 1 до 12 для января-декабря (т. Е. Только по григорианскому календарю).

Олив
источник
скажем, у вас есть строковый месяц май на французском языке, используя метод, который вы опубликовали (май на французском языке - это май), как я могу получить число 5 из этой строки?
usertest 03
@usertest я написал черновой проект класса MonthDelocalizerв моем ответе , чтобы получить Monthобъект из прошедшей локализованного имени месяца строки: mai→ Month.MAY. Обратите внимание, что чувствительность к регистру имеет значение: во французском языке Maiэто недопустимо и должно быть mai.
Basil Bourque
Это 2019 год. Почему это не главный ответ?
anothernode
16

Я бы использовал SimpleDateFormat. Кто-то поправит меня, если есть более простой способ сделать ежемесячный календарь, я делаю это сейчас в коде, и я в этом не уверен.

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());
}
стивидбраун
источник
Эти ужасные классы теперь являются устаревшими, полностью вытесненными современными классами java.time, определенными в JSR 310.
Бэзил Бурк,
14

Вот как бы я это сделал. Я оставлю проверку дальности 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];
}
Билл Ящерица
источник
12

Использование 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"); 

Результат: февраль

Теренс
источник
7

Видимо в Android 2.2 есть ошибка SimpleDateFormat.

Чтобы использовать названия месяцев, вы должны сами определить их в своих ресурсах:

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

А затем используйте их в своем коде следующим образом:

/**
 * 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
источник
«По-видимому, в Android 2.2 есть ошибка» - было бы полезно, если бы вы могли указать, где отслеживается ошибка.
Питер Холл
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

Теперь гораздо проще сделать это в классах java.time, которые вытесняют эти утомительные старые устаревшие классы даты и времени.

MonthПеречисление определяет дюжину объектов, по одному на каждый месяц.

С января по декабрь месяцы пронумерованы с 1 по 12.

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

Попросите объект сгенерировать строку автоматически локализованную названия месяца .

Настроить TextStyle чтобы указать, как долго или сокращенно вы хотите имя. Обратите внимание, что на некоторых языках (не на английском) название месяца меняется, если оно используется отдельно или как часть полной даты. Таким образом, у каждого стиля текста есть свой …_STANDALONEвариант.

Укажите Locale чтобы определить:

  • Какой человеческий язык следует использовать при переводе.
  • Какие культурные нормы должны определять такие вопросы, как аббревиатуры, пунктуация и использование заглавных букв.

Пример:

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

Имя → Month объект

FYI, пойти в другом направлении (разбор строки имени месяца для получения Monthобъекта перечисления) не встроен. Вы можете написать свой собственный класс для этого. Вот моя быстрая попытка пройти такой урок.Используйте на свой риск . Я не задумывался над этим кодом и не тестировал его.

Использование.

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

Код.

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

Около java.time

Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как java.util.Date, Calendar, иSimpleDateFormat .

Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поищите в Stack Overflow множество примеров и объяснений. Спецификация JSR 310 .

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*занятиях.

Где взять классы java.time?

  • Java SE 8 , Java SE 9 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • В Java 9 добавлены некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранней версии Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). См. Как использовать ThreeTenABP… .

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательной площадкой для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval, YearWeek, YearQuarter, и более .

Василий Бурк
источник
1

Возникает проблема, когда вы используете класс DateFormatSymbols для его метода getMonthName, чтобы получить месяц по имени, он показывает месяц по номеру на некоторых устройствах Android. Я решил эту проблему следующим образом:

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

В классе Java просто вызовите этот массив следующим образом:

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

            }

Удачного кодирования :)

Фахир
источник
1

Расширение Kotlin

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

использование

calendar.get(Calendar.MONTH).toMonthName()
Садда Хусейн
источник
Ужасный Calendarкласс был вытеснен много лет назад классами java.time, определенными в JSR 310.
Бэзил Бурк
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
SimpleDateFormatТем не менее, он использует заведомо проблемный и давно устаревший класс.
Оле В.В.
Эти ужасные классы даты и времени были вытеснены много лет назад классами java.time, определенными в JSR 310.
Бэзил Бурк,
0

Просто вставив строку

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

сделает свое дело.

Кингсли Иджике
источник
2
DateFormatSymbolsявляется частью ужасных классов даты и времени, которые теперь унаследованы с момента принятия JSR 310 . Теперь на смену классам java.time . Предлагать их использование в 2019 году - плохой совет.
Basil
Этот ответ дублирует содержание принятого ответа .
Basil
0

Попробуйте использовать это очень простым способом и назовите его как свою собственную функцию

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
Нет необходимости писать такой код. Java имеет встроенный Month::getDisplayName.
Basil
Нет необходимости писать этот шаблонный код. Проверьте мой ответ, опубликованный выше.
Sadda Hussain