【问题标题】:How do you format the day of the month to say "11th", "21st" or "23rd" (ordinal indicator)?您如何将月份中的日期格式化为“11 日”、“21 日”或“23 日”(序数指示符)?
【发布时间】:2011-04-29 23:48:10
【问题描述】:

我知道这会给我一个数字(112123):

SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");

但是如何格式化一个月中的某一天以包含 ordinal indicator11th21st23rd

【问题讨论】:

  • 作为参考,这些被称为序数 - en.wikipedia.org/wiki/Ordinal_number_(linguistics)
  • 只是为了记录,任何构建响应而不是在表格中查找整个答案的东西几乎不可能本地化为其他语言。
  • 答案有点不正确,请看我的答案。
  • 现代评论:我建议你避免使用SimpleDateFormat 类。它不仅过时了,而且出了名的麻烦。今天我们在java.time, the modern Java date and time API 和它的DateTimeFormatter 中做得更好。
  • 查看数字 API (math.tools/api/numbers)。它支持序数、基数、用不同语言拼写的数字、用各种语言拼写为货币等。

标签: java date simpledateformat ordinal


【解决方案1】:

这是我的答案:

public String getOrdinal(int day) { 
    String ordinal; 
    switch (day % 20) { 
        case 1: 
            ordinal = "st"; 
            break; 
        case 2: 
            ordinal = "nd"; 
            break; 
        case 3: 
            ordinal = "rd"; 
            break; 
        default: 
            ordinal = day > 30 > "st" : "th"; 
    } 
    return ordinal; 
} 

只需对 20 进行模运算,它就适用于所有日期。 要获得今天的日期,您可以使用LocalDate.now().getDayOfMonth()。 或者像这样度过任何一天

LocalDate.getDayOfMonth()

【讨论】:

  • @OleV.V.感谢您指出这个错误!我在实时应用程序中使用此代码,我将在那里更正它。我已经发布了正确的代码。请检查
  • 在我看来,您的代码现在从 1 到 31 是正确的。只是不是最容易理解的。请允许我建议您编写一个单元测试。此外,如果day 小于 1 或大于 31,我还想添加范围检查并抛出异常,因为该方法并不总是为这些数字产生预期的结果。
  • @OleV.V.在这里,我假设我们正在通过 LocalDate 的那一天,所以这一天将在 1 到 31 的范围内
【解决方案2】:
public static String getReadableDate(final int date){
    String suffix = "th";
    switch (date){
        case 1:
        case 21:
        case 31:
            suffix = "st";
            break;
        case 2:
        case 22:
            suffix = "nd";
            break;
        case 3:
        case 23:
            suffix = "rd";
            break;
    }
    return date + suffix;
}

【讨论】:

  • 感谢您的贡献。和the existing asnwer by sivag 1有本质区别吗?
  • 嘿@OleV.V.不,没有根本区别。但是,我觉得这更清晰,更易于理解。但这可能是我的观点。如果社区看不到任何价值,我可以将其删除。
【解决方案3】:

对于 Kotlin 试试这个

fun Int.ordinalAbbrev() =
        if (this % 100 / 10 == 1) "th"
        else when (this % 10) { 1 -> "st" 2 -> "nd" 3 -> "rd" else -> "th" }

它接受 int 值并像这样返回 '3rd' '1st' '11th' '2nd'。 所以你也可以将它用于日期格式。

用法

fun getFormatedDate(date: String): String {
        date.let {
            try {
                val parser = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
                val formatter = SimpleDateFormat("dd MMMM", Locale.getDefault())
                val dateArray = formatter.format(parser.parse(it)).split(" ").toTypedArray()
                val formatedDate = String.format(
                    "${dateArray[0]}${
                        dateArray[0].toInt().ordinalAbbrev()
                    } ${dateArray[1]}"
                )

                return formatedDate
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return date
    }

【讨论】:

  • 不确定您是否注意到 - OP 是用 Java 编写的?并且已经回答了 21 次。你回答了哪些其他人没有回答的问题?
  • 我不了解其他人。但我的答案是针对 kotlin 开发人员的,它更有帮助。
  • 您能否更新答案@AzizEjaz 以提及 Kotlin。
【解决方案4】:

使用新的java.time 包和更新的Java switch 语句,以下很容易允许将序数放置在一个月中的某一天。一个缺点是这不适用于DateFormatter 类中指定的固定格式。

只需创建某种格式的日期,但包括 %s%s 以稍后添加日期和序号。

ZonedDateTime ldt = ZonedDateTime.now();
String format = ldt.format(DateTimeFormatter
        .ofPattern("EEEE, MMMM '%s%s,' yyyy hh:mm:ss a zzz"));

现在将星期几和刚刚格式化的日期传递给辅助方法以添加序数日。


int day = ldt.getDayOfMonth();
System.out.println(applyOrdinalDaySuffix(format, day));

打印

Tuesday, October 6th, 2020 11:38:23 AM EDT

这里是辅助方法。

使用Java 14 switch expressions 可以很容易地获取序数。

public static String applyOrdinalDaySuffix(String format,
        int day) {
    if (day < 1 || day > 31)
        throw new IllegalArgumentException(
                String.format("Bad day of month (%s)", day));
    String ord = switch (day) {
        case 1, 21, 31 -> "st";
        case 2, 22 -> "nd";
        case 3, 23 -> "rd";
        default -> "th";
    };
    
    return String.format(format, day, ord);
}

【讨论】:

    【解决方案5】:

    试试下面的功能:

    public static String getFormattedDate(Date date) 
    {
      Calendar cal = Calendar.getInstance();
      cal.setTime(date);
      //2nd of march 2015
      int day = cal.get(Calendar.DATE);
      if (!((day > 10) && (day < 19)))
       switch (day % 10) {
        case 1:
         return new SimpleDateFormat("d'st' 'of' MMMM yyyy").format(date);
        case 2:
         return new SimpleDateFormat("d'nd' 'of' MMMM yyyy").format(date);
        case 3:
         return new SimpleDateFormat("d'rd' 'of' MMMM yyyy").format(date);
        default:
         return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
       }
      return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
    }
    

    【讨论】:

    • 在回答一个老问题时,如果您包含一些上下文来解释您的答案如何提供帮助,那么您的答案将对其他 StackOverflow 用户更有用,特别是对于已经有一个已接受答案的问题。请参阅:How do I write a good answer
    • 感谢您的贡献。我建议我们不要使用DateCalendarSimpleDateFormat。这些类设计不良且过时,尤其是最后一个以麻烦着称。而是使用来自java.time, the modern Java date and time APILocalDateDateTimeFormatter。我也怀疑与其他 18 个答案相比,您的答案有什么新贡献?
    • 对于 12thi,它将打印“12nd”,这是不正确的。 13 日也是如此
    【解决方案6】:

    RuleBasedNumberFormat ICU 图书馆中

    我很欣赏@Pierre-Olivier Dybman (http://www.icu-project.org/apiref/icu4j/com/ibm/icu/text/RuleBasedNumberFormat.html) 提供的 ICU 项目库链接,但仍然需要弄清楚如何使用它,所以下面是 RuleBasedNumberFormat 用法的示例。

    它只会格式化单个数字而不是整个日期,因此如果要查找格式为以下格式的日期,则需要构建一个组合字符串:例如,2 月 3 日星期一。

    以下代码将RuleBasedNumberFormat 设置为给定区域设置的序数格式,创建java.time ZonedDateTime,然后将数字及其序数格式化为字符串。

    RuleBasedNumberFormat numOrdinalFormat = new RuleBasedNumberFormat(Locale.UK,
        RuleBasedNumberFormat.ORDINAL);
    ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Pacific/Auckland"));
    
    String dayNumAndOrdinal = numOrdinalFormat.format(zdt.toLocalDate().getDayOfMonth());
    

    示例输出:

    第三

    或者

    第四个

    等等

    【讨论】:

      【解决方案7】:

      我想提供现代答案。 SimpleDateFormat 类在 8 年前被问到这个问题时可以使用,但你现在应该避免使用它,因为它不仅已经过时了,而且出了名的麻烦。请改用java.time

      编辑

      DateTimeFormatterBuilder.appendText(TemporalField, Map&lt;Long, String&gt;) 非常适合此目的。使用它,我们构建了一个为我们工作的格式化程序:

          Map<Long, String> ordinalNumbers = new HashMap<>(42);
          ordinalNumbers.put(1L, "1st");
          ordinalNumbers.put(2L, "2nd");
          ordinalNumbers.put(3L, "3rd");
          ordinalNumbers.put(21L, "21st");
          ordinalNumbers.put(22L, "22nd");
          ordinalNumbers.put(23L, "23rd");
          ordinalNumbers.put(31L, "31st");
          for (long d = 1; d <= 31; d++) {
              ordinalNumbers.putIfAbsent(d, "" + d + "th");
          }
      
          DateTimeFormatter dayOfMonthFormatter = new DateTimeFormatterBuilder()
                  .appendText(ChronoField.DAY_OF_MONTH, ordinalNumbers)
                  .appendPattern(" MMMM")
                  .toFormatter();
      
          LocalDate date = LocalDate.of(2018, Month.AUGUST, 30);
          for (int i = 0; i < 6; i++) {
              System.out.println(date.format(dayOfMonthFormatter));
              date = date.plusDays(1);
          }
      

      这个 sn-p 的输出是:

      30th August
      31st August
      1st September
      2nd September
      3rd September
      4th September
      

      旧答案

      这段代码更短,但恕我直言,不是那么优雅。

          // ordinal indicators by numbers (1-based, cell 0 is wasted)
          String[] ordinalIndicators = new String[31 + 1];
          Arrays.fill(ordinalIndicators, 1, ordinalIndicators.length, "th");
          ordinalIndicators[1] = ordinalIndicators[21] = ordinalIndicators[31] = "st";
          ordinalIndicators[2] = ordinalIndicators[22] = "nd";
          ordinalIndicators[3] = ordinalIndicators[23] = "rd";
      
          DateTimeFormatter dayOfMonthFormatter = DateTimeFormatter.ofPattern("d");
      
          LocalDate today = LocalDate.now(ZoneId.of("America/Menominee")).plusWeeks(1);
          System.out.println(today.format(dayOfMonthFormatter) 
                              + ordinalIndicators[today.getDayOfMonth()]);
      

      刚刚运行这个sn-p我得到了

      23日

      java.time 的众多功能之一是它可以直接且可靠地以 int 形式获取月份中的某天,这显然是从表中选择正确后缀所必需的。

      我建议你也写一个单元测试。

      PS 类似的格式化程序也可用于解析包含诸如1st2nd 等序数的日期字符串。这是在@987654321 中完成的@。

      链接:Oracle tutorial: Date Time解释如何使用java.time

      【讨论】:

      • 希望这个答案更高,因为这个更现代的答案比尝试推出自己的实现更好。
      【解决方案8】:

      如果您尝试了解 i18n,解决方案会变得更加复杂。

      问题在于,在其他语言中,后缀可能不仅取决于数字本身,还取决于它所计数的名词。例如,在俄语中它会是“2-ой день”,但是“2-ая неделя”(这些意思是“第 2 天”,但“第 2 周”)。如果我们只格式化日期,这不适用,但在更一般的情况下,您应该注意复杂性。

      我认为很好的解决方案(我没有时间实际实施)是扩展 SimpleDateFormetter 以在传递给父类之前应用区域设置感知 MessageFormat。这样,您就可以支持假设 March 格式 %M 获得“3-rd”,%MM 获得“03-rd”和 %MMM 获得“third”。从外部看,这个类看起来像普通的 SimpleDateFormatter,但支持更多格式。此外,如果常规 SimpleDateFormetter 错误地应用此模式,则结果的格式将不正确,但仍然可读。

      【讨论】:

      • 关于俄语中性别的观点很好,但从技术上讲,如果没有额外的上下文,这会使 %MMM 不可能。
      • @Mad Physicist,这是不正确的,因为 %MMM 将应用于月份,所以我们知道要共轭的名词。
      【解决方案9】:

      我为自己编写了一个辅助方法来获取模式。

      public static String getPattern(int month) {
          String first = "MMMM dd";
          String last = ", yyyy";
          String pos = (month == 1 || month == 21 || month == 31) ? "'st'" : (month == 2 || month == 22) ? "'nd'" : (month == 3 || month == 23) ? "'rd'" : "'th'";
          return first + pos + last;
      }
      

      然后我们可以称之为

      LocalDate localDate = LocalDate.now();//For reference
      int month = localDate.getDayOfMonth();
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern(getPattern(month));
      String date = localDate.format(formatter);
      System.out.println(date);
      

      输出是

      December 12th, 2018
      

      【讨论】:

      • 这需要至少 26 个 API :)
      • @MikkelLarsen 这个问题与 android 无关,我为此使用了 Java 8。 Android 不支持 java 8 的大型 api。
      • @SamSakerz 我的错 :)
      • @MikkelLarsen 大多数java.time 功能在ThreeTen-Backport 项目中被反向移植到Java 6 和Java 7。进一步适用于ThreeTenABP 中的早期 Android (How to use ThreeTenABP…
      【解决方案10】:

      这是一种方法,如果找到模式 d'00',则使用正确的后缀文字更新 DateTimeFormatter 模式,例如对于第 1 个月的一天,它将被替换为 d'st'。一旦模式被更新,它就可以被送入 DateTimeFormatter 来完成剩下的工作。

      private static String[] suffixes = {"th", "st", "nd", "rd"};
      
      private static String updatePatternWithDayOfMonthSuffix(TemporalAccessor temporal, String pattern) {
          String newPattern = pattern;
          // Check for pattern `d'00'`.
          if (pattern.matches(".*[d]'00'.*")) {
              int dayOfMonth = temporal.get(ChronoField.DAY_OF_MONTH);
              int relevantDigits = dayOfMonth < 30 ? dayOfMonth % 20 : dayOfMonth % 30;
              String suffix = suffixes[relevantDigits <= 3 ? relevantDigits : 0];
              newPattern = pattern.replaceAll("[d]'00'", "d'" + suffix + "'");
          }
      
          return newPattern;
      }
      

      它确实需要在每次格式化调用之前更新原始模式,例如

      public static String format(TemporalAccessor temporal, String pattern) {
          DateTimeFormatter formatter = DateTimeFormatter.ofPattern(updatePatternWithDayOfMonthSuffix(temporal, pattern));
          return formatter.format(temporal);
      }
      

      因此,如果格式化模式是在 Java 代码之外定义的,例如一个模板,好像您可以在 Java 中定义模式,然后由@OleV.V 给出答案。可能更合适

      【讨论】:

      • 创意和复杂。我确实花了很长时间才理解它是如何工作的。这不是好代码的标志。
      • @OleV.V. thx 的反馈 - 我已经对其进行了一些重组,因此它的冗长程度有所降低。刚刚看到你的方法,我喜欢它!我认为这两种方法在不同的权衡下都是有效的。您的在格式化时不需要任何进一步的支持,但确实需要使用排除非 Java 代码中的模式定义的构建器来定义模式。我的方法在格式化时确实需要额外的支持,但不依赖于构建器来创建模式,因此在可以定义模式的地方更加灵活。我的要求决定了后者
      • 很好地说明了利弊。您可能希望将其包含在答案中?只是一个想法。
      【解决方案11】:
      String ordinal(int num)
      {
          String[] suffix = {"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"};
          int m = num % 100;
          return String.valueOf(num) + suffix[(m > 3 && m < 21) ? 0 : (m % 10)];
      }
      

      【讨论】:

        【解决方案12】:

        问题有点老了。由于这个问题非常嘈杂,所以将我用静态方法解决的问题作为实用程序发布。只需复制、粘贴并使用它!

         public static String getFormattedDate(Date date){
                    Calendar cal=Calendar.getInstance();
                    cal.setTime(date);
                    //2nd of march 2015
                    int day=cal.get(Calendar.DATE);
        
                    if(!((day>10) && (day<19)))
                    switch (day % 10) {
                    case 1:  
                        return new SimpleDateFormat("d'st' 'of' MMMM yyyy").format(date);
                    case 2:  
                        return new SimpleDateFormat("d'nd' 'of' MMMM yyyy").format(date);
                    case 3:  
                        return new SimpleDateFormat("d'rd' 'of' MMMM yyyy").format(date);
                    default: 
                        return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
                }
                return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
            }
        

        用于测试目的

        示例:从 main 方法调用它!

        Date date = new Date();
                Calendar cal=Calendar.getInstance();
                cal.setTime(date);
                for(int i=0;i<32;i++){
                  System.out.println(getFormattedDate(cal.getTime()));
                  cal.set(Calendar.DATE,(cal.getTime().getDate()+1));
                }
        

        输出:

        22nd of February 2018
        23rd of February 2018
        24th of February 2018
        25th of February 2018
        26th of February 2018
        27th of February 2018
        28th of February 2018
        1st of March 2018
        2nd of March 2018
        3rd of March 2018
        4th of March 2018
        5th of March 2018
        6th of March 2018
        7th of March 2018
        8th of March 2018
        9th of March 2018
        10th of March 2018
        11th of March 2018
        12th of March 2018
        13th of March 2018
        14th of March 2018
        15th of March 2018
        16th of March 2018
        17th of March 2018
        18th of March 2018
        19th of March 2018
        20th of March 2018
        21st of March 2018
        22nd of March 2018
        23rd of March 2018
        24th of March 2018
        25th of March 2018
        

        【讨论】:

          【解决方案13】:

          在 kotlin 中你可以这样使用

          fun changeDateFormats(currentFormat: String, dateString: String): String {
                  var result = ""
                  try {
                      val formatterOld = SimpleDateFormat(currentFormat, Locale.getDefault())
                      formatterOld.timeZone = TimeZone.getTimeZone("UTC")
          
                      var date: Date? = null
          
                      date = formatterOld.parse(dateString)
          
                      val dayFormate = SimpleDateFormat("d", Locale.getDefault())
                      var day = dayFormate.format(date)
          
                      val formatterNew = SimpleDateFormat("hh:mm a, d'" + getDayOfMonthSuffix(day.toInt()) + "' MMM yy", Locale.getDefault())
          
                      if (date != null) {
                          result = formatterNew.format(date)
                      }
          
                  } catch (e: ParseException) {
                      e.printStackTrace()
                      return dateString
                  }
          
                  return result
              }
          
          
              private fun getDayOfMonthSuffix(n: Int): String {
                  if (n in 11..13) {
                      return "th"
                  }
                  when (n % 10) {
                      1 -> return "st"
                      2 -> return "nd"
                      3 -> return "rd"
                      else -> return "th"
                  }
              }
          

          这样设置

            txt_chat_time_me.text = changeDateFormats("SERVER_DATE", "DATE")
          

          【讨论】:

            【解决方案14】:

            我无法满足要求基于手动格式的纯英文解决方案的答案。我一直在寻找合适的解决方案,终于找到了。

            您应该使用RuleBasedNumberFormat。它运行良好,并且尊重语言环境。

            【讨论】:

              【解决方案15】:
              // https://github.com/google/guava
              import static com.google.common.base.Preconditions.*;
              
              String getDayOfMonthSuffix(final int n) {
                  checkArgument(n >= 1 && n <= 31, "illegal day of month: " + n);
                  if (n >= 11 && n <= 13) {
                      return "th";
                  }
                  switch (n % 10) {
                      case 1:  return "st";
                      case 2:  return "nd";
                      case 3:  return "rd";
                      default: return "th";
                  }
              }
              

              来自@kaliatech 的表格很不错,但由于重复了相同的信息,它为错误打开了机会。 7tn17tn27tn 的表中实际上存在这样的错误(由于 StackOverflow 的流动性,随着时间的推移,此错误可能会得到修复,因此请检查 the version history on the answer 以查看错误)。

              【讨论】:

              • 真的感觉像是对简单数据格式的疏忽,不是吗?
              • 享受国际化的乐趣。 :D
              • @Trejkaz 在问题范围之外:)
              • 此方案仅支持英文。使用 ICU4J 中的 RuleBasedNumberFormat 获得本地化解决方案。
              • 你们在杂草丛中,语气有点转变。没必要。这个问题没有问国际化的复杂性。国际化当然是一个值得讨论的好话题,但应该在另一个具有该重点的问题上进行。我一直将这个问题解释为要求一种快速而肮脏的方式来用英语完成此任务。因此,我建议,如果 Java 世界中确实没有对国际化友好的好的解决方案,我们可以在例如 GitHub 上启动一个项目并创建一个好的解决方案。如果您有兴趣,请告诉我。
              【解决方案16】:

              JDK 中没有任何东西可以做到这一点。

                static String[] suffixes =
                //    0     1     2     3     4     5     6     7     8     9
                   { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th",
                //    10    11    12    13    14    15    16    17    18    19
                     "th", "th", "th", "th", "th", "th", "th", "th", "th", "th",
                //    20    21    22    23    24    25    26    27    28    29
                     "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th",
                //    30    31
                     "th", "st" };
              
               Date date = new Date();
               SimpleDateFormat formatDayOfMonth  = new SimpleDateFormat("d");
               int day = Integer.parseInt(formatDateOfMonth.format(date));
               String dayStr = day + suffixes[day];
              

              或者使用日历:

               Calendar c = Calendar.getInstance();
               c.setTime(date);
               int day = c.get(Calendar.DAY_OF_MONTH);
               String dayStr = day + suffixes[day];
              

              @thorbjørn-ravn-andersen 根据 cmets 的说法,这样的表格在本地化时会很有帮助:

                static String[] suffixes =
                   {  "0th",  "1st",  "2nd",  "3rd",  "4th",  "5th",  "6th",  "7th",  "8th",  "9th",
                     "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th",
                     "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th",
                     "30th", "31st" };
              

              【讨论】:

              • 如果您让表格包含完整的“21st”、“23rd”、“29th”,则可以将其外部化并本地化为其他语言。对于可能成为要求的成功软件。
              【解决方案17】:

              以下方法可用于获取传递给它的日期的格式化字符串。它会在 Java 中使用 SimpleDateFormat 将日期格式化为 1st、2nd、3rd、4th ..。例如:- 2015 年 9 月 1 日

              public String getFormattedDate(Date date){
                          Calendar cal=Calendar.getInstance();
                          cal.setTime(date);
                          //2nd of march 2015
                          int day=cal.get(Calendar.DATE);
              
                          switch (day % 10) {
                          case 1:  
                              return new SimpleDateFormat("d'st' 'of' MMMM yyyy").format(date);
                          case 2:  
                              return new SimpleDateFormat("d'nd' 'of' MMMM yyyy").format(date);
                          case 3:  
                              return new SimpleDateFormat("d'rd' 'of' MMMM yyyy").format(date);
                          default: 
                              return new SimpleDateFormat("d'th' 'of' MMMM yyyy").format(date);
                      }
              

              【讨论】:

                【解决方案18】:

                此处的许多示例不适用于 11、12、13。这更通用,适用于所有情况。

                switch (date) {
                                case 1:
                                case 21:
                                case 31:
                                    return "" + date + "st";
                
                                case 2:
                                case 22:
                                    return "" + date + "nd";
                
                                case 3:
                                case 23:
                                    return "" + date + "rd";
                
                                default:
                                    return "" + date + "th";
                }
                

                【讨论】:

                • 工作得很好也很简单,谢谢
                【解决方案19】:

                以下是对问题的更有效的答案,而不是对样式进行硬编码。

                要将日期更改为序数,您需要使用以下suffix

                DD +     TH = DDTH  result >>>> 4TH
                
                OR to spell the number add SP to the format
                
                DD + SPTH = DDSPTH   result >>> FOURTH
                

                this 问题中找到我的完整答案。

                【讨论】:

                【解决方案20】:

                Greg 提供的解决方案的唯一问题是它不考虑大于 100 且以“teen”数字结尾的数字。例如,111 应该是第 111 个,而不是第 111 个。这是我的解决方案:

                /**
                 * Return ordinal suffix (e.g. 'st', 'nd', 'rd', or 'th') for a given number
                 * 
                 * @param value
                 *           a number
                 * @return Ordinal suffix for the given number
                 */
                public static String getOrdinalSuffix( int value )
                {
                    int hunRem = value % 100;
                    int tenRem = value % 10;
                
                    if ( hunRem - tenRem == 10 )
                    {
                        return "th";
                    }
                    switch ( tenRem )
                    {
                    case 1:
                        return "st";
                    case 2:
                        return "nd";
                    case 3:
                        return "rd";
                    default:
                        return "th";
                    }
                }
                

                【讨论】:

                • 在什么情况下 Day Month 序列会超过 31 天??
                • @SatanEnglish,这个静态工厂方法的好处是,它可以用于不止一个月的后缀。 :)
                • 此方法返回 st 表示 11,nd 表示 12,rd 表示 13
                • @SatanEnglish。鉴于今天是我选择的日历中的 2 月 137 日,我认为您的问题可以自行回答。不过说真的,如果你知道去哪里看,非公历比比皆是。
                • 不,@TheIT,它没有。我测试过。它应该为 11、12 和 13 返回th。我相信if ( hunRem - tenRem == 10 ) 案例可以确保它确实如此。
                【解决方案21】:
                public String getDaySuffix(int inDay)
                {
                  String s = String.valueOf(inDay);
                
                  if (s.endsWith("1"))
                  {
                    return "st";
                  }
                  else if (s.endsWith("2"))
                  {
                    return "nd";
                  }
                  else if (s.endsWith("3"))
                  {
                    return "rd";
                  }
                  else
                  {
                    return "th";
                  }
                }
                

                【讨论】:

                • 不应该使用endsWith();产生错误的输出
                【解决方案22】:
                private String getCurrentDateInSpecificFormat(Calendar currentCalDate) {
                    String dayNumberSuffix = getDayNumberSuffix(currentCalDate.get(Calendar.DAY_OF_MONTH));
                    DateFormat dateFormat = new SimpleDateFormat(" d'" + dayNumberSuffix + "' MMMM yyyy");
                    return dateFormat.format(currentCalDate.getTime());
                }
                
                private String getDayNumberSuffix(int day) {
                    if (day >= 11 && day <= 13) {
                        return "th";
                    }
                    switch (day % 10) {
                    case 1:
                        return "st";
                    case 2:
                        return "nd";
                    case 3:
                        return "rd";
                    default:
                        return "th";
                    }
                }
                

                【讨论】:

                • 我刚刚尝试了您的解决方案,同时省略了提供给 SimpleDateFormat 构造函数的模式字符串中的单引号。我现在明白他们为什么在那里了。由于“非法模式字符 t”,我收到了 java.lang.IllegalArgumentException
                【解决方案23】:

                有一种更简单、更可靠的方法来做到这一点。您需要使用的函数是 getDateFromDateString(dateString);它基本上从日期字符串中删除了 st/nd/rd/th 并简单地解析它。您可以将您的 SimpleDateFormat 更改为任何内容,这将起作用。

                public static final SimpleDateFormat sdf = new SimpleDateFormat("d");
                public static final Pattern p = Pattern.compile("([0-9]+)(st|nd|rd|th)");
                
                private static Date getDateFromDateString(String dateString) throws ParseException {
                     return sdf.parse(deleteOrdinal(dateString));
                }
                
                private static String deleteOrdinal(String dateString) {
                    Matcher m = p.matcher(dateString);
                    while (m.find()) {
                        dateString = dateString.replaceAll(Matcher.quoteReplacement(m.group(0)), m.group(1));
                    }
                    return dateString;
                

                }

                【讨论】:

                • 这个答案是关于 parsing 一个字符串,而问题是关于 generating 一个字符串。但仍然合适,因为一个人可能需要两个方向。另外,这个答案解决了this other Question
                猜你喜欢
                • 1970-01-01
                • 2020-10-18
                • 2022-01-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-11-25
                • 1970-01-01
                相关资源
                最近更新 更多