【问题标题】:How can I convert an Integer to localized month name in Java?如何在 Java 中将整数转换为本地化月份名称?
【发布时间】:2009-06-24 14:00:50
【问题描述】:

我得到一个整数,我需要在不同的语言环境中转换为月份名称:

地区 en-us 示例:
1 -> 一月
2 -> 二月

区域设置 es-mx 的示例:
1 -> 埃内罗
2 -> 费布雷罗

【问题讨论】:

  • 注意,Java 月份是从零开始的,所以 0 = 一月,1 = 二月,等等
  • 你是对的,所以如果需要更改语言,只需更改语言环境即可。谢谢
  • @NickHolt UPDATE 现代的 java.timeMonth 枚举是从 1 开始的:1-12 月为 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 类所取代。

标签: java date locale


【解决方案1】:
import java.text.DateFormatSymbols;
public String getMonth(int month) {
    return new DateFormatSymbols().getMonths()[month-1];
}

【讨论】:

  • 你不需要'month-1',因为数组是从零开始的吗? atomfat 想要 1 -> 1 月等。
  • 他确实需要month-1,因为月份是从1开始的月份数,需要转换为从零开始的数组位置
  • public String getMonth(int month, Locale locale) { return DateFormatSymbols.getInstance(locale).getMonths()[month-1]; }
  • HE 需要month-1。其他使用Calendar.get(Calendar.MONTH) 的人只需要month
  • DateFormatSymbols 实现在 JDK 8 中已更改,因此 getMonths 方法不再为所有区域设置返回正确的值:oracle.com/technetwork/java/javase/…
【解决方案2】:

tl;博士

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(或带有 ThreeTen-Backport 的 1.7 和 1.6)开始,您可以使用这个:

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

请注意,integerMonth 是从 1 开始的,即 1 表示一月。 1 月至 12 月的范围始终为 1 到 12(即仅公历)。

【讨论】:

  • 假设您使用您发布的方法在法语中有五月的字符串月份(法语中的五月是 Mai),我怎样才能从这个字符串中获得数字 5??
  • @usertest 我在my Answer 中编写了一个草稿类MonthDelocalizer 以从传递的本地化月份名称字符串中获取Month 对象:mai → Month.MAY。请注意区分大小写:在法语中,Mai 无效,应为 mai
  • 现在是 2019 年。这怎么不是最佳答案?
  • 不适合我。结果不是月份的名称,而是月份的编号。您需要使用TextStyle.FULL 才能工作。
  • @Dherik 我相信这是一个 JDK 错误。 TextStyle.FULLFULL_STANDALONE 都定义为返回“完整的文本”,请参阅here。你使用什么语言?用我的语言(斯洛伐克语)FULL 以属格形式给出月份名称,这在完整日期中使用时很好。 FULL_STANDALONE 以主格形式给出,这很好,例如用于在列表框中进行选择。
【解决方案3】:

您需要为独立的月份名称使用 LLLL。这在SimpleDateFormat 文档中有记录,例如:

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

【讨论】:

  • JDK 1.7 / IllegalArgumentException : Illegal pattern character 'L'
【解决方案4】:

我会使用 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());
}

【讨论】:

  • 这些糟糕的类现在已经遗留下来,完全被 JSR 310 中定义的现代 java.time 类所取代。
【解决方案5】:

我会这样做。 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];
}

【讨论】:

    【解决方案6】:

    使用 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;
      }
      

      【讨论】:

      • “显然在 Android 2.2 中存在一个错误” — 如果您可以链接到跟踪错误的位置,将会很有用。
      【解决方案8】:

      tl;博士

      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.
      

      要求对象生成name of the month, automatically localized 的字符串。

      调整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 对象

      仅供参考,不是内置的(解析月份名称字符串以获取 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 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

      Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

      要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

      您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

      从哪里获得 java.time 类?

      • Java SE 8Java SE 9 及更高版本
        • 内置。
        • 标准 Java API 的一部分,带有捆绑实现。
        • Java 9 添加了一些小功能和修复。
      • Java SE 6Java SE 7
        • ThreeTen-Backport 中的大部分 java.time 功能都向后移植到 Java 6 和 7。
      • Android
        • java.time 类的 Android 捆绑包实现的更高版本。
        • 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

      ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

      【讨论】:

        【解决方案9】:

        当您将 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);
        
                    }
        

        快乐编码:)

        【讨论】:

          【解决方案10】:

          Kotlin 扩展

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

          用法

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

          【讨论】:

          • 可怕的 Calendar 类在多年前被 JSR 310 中定义的 java.time 类所取代。
          【解决方案11】:
              public static void main(String[] args) {
              SimpleDateFormat format = new SimpleDateFormat("MMMMM", new Locale("en", "US"));
              System.out.println(format.format(new Date()));
          }
          

          【讨论】:

          • 这似乎是正确的答案,但你能解释一下你是做什么的以及为什么这样做吗?
          • 我这样做是因为我觉得简单而不复杂!
          • 不过,它使用了臭名昭著的麻烦且早已过时的SimpleDateFormat 类。
          • 这些可怕的日期时间类在几年前被 JSR 310 中定义的 java.time 类所取代。
          【解决方案12】:

          只插入一行

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

          会成功的。

          【讨论】:

          【解决方案13】:

          尝试使用这个非常简单的方法,并像你自己的函数一样调用它

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

          【讨论】:

          • 这种代码不用写。 Java 内置了Month::getDisplayName
          • 无需编写此样板代码。检查我上面发布的答案。
          猜你喜欢
          • 2013-03-08
          • 1970-01-01
          • 1970-01-01
          • 2012-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多