У меня есть LocalDate
, который содержит дату 2012-12-28, и я хочу напечатать его с локализованным именем месяца (т.е. декабрь на польском языке) в родительном падеже, который по-польски отличается от именительного (grudnia и grudzień соответственно). Поскольку я также хочу использовать пользовательский формат, я создал свой собственный DateTimeFormatter
с помощью DateTimeFormatterBuilder
(который AFAIK - правильный путь к нему в Joda-Time):
private static final DateTimeFormatter CUSTOM_DATE_FORMATTER
= new DateTimeFormatterBuilder()
.appendLiteral("z dnia ")
.appendDayOfMonth(1)
.appendLiteral(' ')
.appendText(new MonthNameGenitive()) // <--
.appendLiteral(' ')
.appendYear(4, 4)
.appendLiteral(" r.")
.toFormatter()
.withLocale(new Locale("pl", "PL")); // not used in this case apparently
Выход должен быть "z dnia 28 grudnia 2012 r.".
Мой вопрос о строке, отмеченной стрелкой: как мне реализовать MonthNameGenitive
? В настоящее время он расширяет DateTimeFieldType
и имеет довольно много кода:
final class MonthNameGenitive extends DateTimeFieldType {
private static final long serialVersionUID = 1L;
MonthNameGenitive() {
super("monthNameGenitive");
}
@Override
public DurationFieldType getDurationType() {
return DurationFieldType.months();
}
@Override
public DurationFieldType getRangeDurationType() {
return DurationFieldType.years();
}
@Override
public DateTimeField getField(final Chronology chronology) {
return new MonthNameGenDateTimeField(chronology.monthOfYear());
}
private static final class MonthNameGenDateTimeField
extends DelegatedDateTimeField {
private static final long serialVersionUID = 1L;
private static final ImmutableList<String> MONTH_NAMES =
ImmutableList.of(
"stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca",
"lipca", "sierpnia", "września", "października", "listopada",
"grudnia");
private MonthNameGenDateTimeField(final DateTimeField field) {
super(field);
}
@Override
public String getAsText(final ReadablePartial partial,
final Locale locale) {
return MONTH_NAMES.get(
partial.get(this.getType()) - 1); // months are 1-based
}
}
}
Кажется неаккуратным и не пуленевым для меня, так как мне пришлось реализовать множество магических методов, плюс я использую DelegatedDateTimeField
и переопределяя только один метод (getAsText(ReadablePartial, Locale)
), в то время как есть другие с тем же именем:
-
getAsText(long, Locale)
-
getAsText(long)
-
getAsText(ReadablePartial, int, Locale)
-
getAsText(int, Locale)
Есть ли лучший подход для получения желаемого результата (с использованием DateTimeFormatter
) или мой подход правильный, но очень подробный?
EDIT:
Я попытался добиться того же, что и новый JDK8 Time API (который похож на Joda, основанный на JSR-310), и это можно сделать легко:
private static final java.time.format.DateTimeFormatter JDK8_DATE_FORMATTER
= new java.time.format.DateTimeFormatterBuilder()
.appendLiteral("z dnia ")
.appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NORMAL)
.appendLiteral(' ')
.appendText(ChronoField.MONTH_OF_YEAR, MONTH_NAMES_GENITIVE) // <--
.appendLiteral(' ')
.appendValue(ChronoField.YEAR, 4)
.appendLiteral(" r.")
.toFormatter()
.withLocale(new Locale("pl", "PL"));
где MONTH_NAMES_GENITIVE
есть Map<Long, String>
с пользовательскими именами месяцев, поэтому он очень прост в использовании. См. DateTimeFormatterBuilder#appendText(TemporalField, Map)
.
Интересно, что в JDK8 вся польза-месяц-родительный падеж не нужна, потому что DateFormatSymbols.getInstance(new Locale("pl", "PL")).getMonths()
возвращает имена месяцев в родительном падеже по умолчанию... Пока это изменение верно для моего варианта использования (по-польски, мы говорим "сегодня 28 декабря 2012 года", используя месячные имена в родительном падеже), это может быть сложно в некоторых других случаях (мы говорим "это декабрь 2012 года" с использованием именительного имени), и это обратно несовместимо.