How do you format the day of the month to say “11th”, “21st” or “23rd” (ordinal indicator)?

后端 未结 20 999
逝去的感伤
逝去的感伤 2020-11-22 02:41

I know this will give me the day of the month as a number (11, 21, 23):

SimpleDateFormat formatDayOfMonth = new Simple         


        
20条回答
  •  鱼传尺愫
    2020-11-22 02:58

    I should like to contribute the modern answer. The SimpleDateFormat class was OK to use when the question was asked 8 years ago, but you should avoid it now as it is not only long outdated, but also notoriously troublesome. Use java.time instead.

    Edit

    DateTimeFormatterBuilder.appendText(TemporalField, Map) is great for this purpose. Using it we build a formatter that does the work for us:

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

    The output from this snippet is:

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

    Old answer

    This code is shorter, but IMHO not so elegant.

        // 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()]);
    

    Running this snippet just now I got

    23rd

    One of the many features of java.time is that it’s straightforward and reliable to get the day of month as an int, which is obviously needed for picking the right suffix from the table.

    I recommend you write a unit test too.

    PS A similar formatter can also be used for parsing a date string containing ordinal numbers like 1st, 2nd, etc. That was done in this question: Java - Parse date with optional seconds.

    Link: Oracle tutorial: Date Time explaining how to use java.time.

提交回复
热议问题