Вопрос-ответ

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

Как вы форматируете день месяца, чтобы сказать "11-е", "21-е" или "23-е" (порядковый номер индикатора)?

Я знаю, что это даст мне день месяца в виде числа (11, 21, 23):

SimpleDateFormat formatDayOfMonth = new SimpleDateFormat("d");

Но как вы форматируете день месяца, чтобы включить порядковый индикатор, скажем 11th, 21st или 23rd?

Переведено автоматически
Ответ 1
// 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 приятная, но поскольку одна и та же информация повторяется, это создает вероятность ошибки. Такая ошибка на самом деле существует в таблице для 7tn, 17tn и 27tn (эта ошибка может быть исправлена со временем из-за изменчивого характера StackOverflow, поэтому проверьте историю версий ответа, чтобы увидеть ошибку).

Ответ 2

В 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, подобная таблица может быть полезна при локализации:

  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" };
Ответ 3
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";
}
}
Ответ 4

Я хотел бы предложить современный ответ. Класс SimpleDateFormat можно было использовать, когда вопрос задавался 8 лет назад, но вам следует избегать его сейчас, поскольку он не только давно устарел, но и, как известно, доставляет много хлопот. Используйте java.time вместо этого.

Редактировать

DateTimeFormatterBuilder.appendText(TemporalField, Map<Long, String>) отлично подходит для этой цели. Используя его, мы создаем программу форматирования, которая выполняет всю работу за нас:

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

Вывод из этого фрагмента выглядит следующим образом:


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

Только что запустив этот фрагмент, я получил


23 - й


Одна из многих особенностей java.time заключается в том, что легко и надежно получить день месяца в виде int, что, очевидно, необходимо для выбора правильного суффикса из таблицы.

Я рекомендую вам также написать модульный тест.

PS Аналогичный форматировщик также можно использовать для синтаксического анализа строки даты, содержащей порядковые номера, такие как 1st, 2nd и т.д. Это было сделано в этом вопросе: Java - анализ даты с необязательными секундами.

Руководство по Oracle: дата и время Ссылка: объяснение использования java.time.

java date