【发布时间】:2013-06-28 18:00:20
【问题描述】:
我有 LocalDate,其中包含日期 2012-12-28,我想用本地化月份名称(即波兰语中的 12 月)属格打印它,这在波兰语中与主格不同(grudnia 和 grudzień)。因为我还想使用自定义格式,所以我使用DateTimeFormatterBuilder 创建了自己的DateTimeFormatter(在 Joda-Time 中,AFAIK 是正确的方法):
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)或者我的方法正确但非常冗长?
编辑:
我尝试使用新的 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 中,整个 Polish-month-name-genitive 播放是不必要的,因为 DateFormatSymbols.getInstance(new Locale("pl", "PL")).getMonths() 默认返回属格的月份名称... 虽然这个更改对我的用例是正确的(在波兰语中,我们说“今天是 2012 年 12 月 28 日”在属格中使用月份名称),在其他一些情况下可能会很棘手(我们说“现在是 2012 年 12 月”使用主格)并且向后不兼容。
【问题讨论】:
-
我实际上有点惊讶,它不知道何时使用属格以及何时使用其他(主格?)版本 - 我们当然会尝试在 Noda Time 中做到这一点。
-
@JonSkeet 似乎在JDK8中通过
TextStyle枚举常量FULL/FULL_STANDALONE支持属格/主格版本,其中FULL是默认值,对于波兰语,它是属格和FULL_STANDALONE是主格 - 另见this XML file with localized names。所以.appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL_STANDALONE)可以用作标准月份名称。