使用Joda-Time DateTimeFormatter的genitive(波兰语语言环境)中的月份名称 [英] Month name in genitive (Polish locale) with Joda-Time DateTimeFormatter

查看:185
本文介绍了使用Joda-Time DateTimeFormatter的genitive(波兰语语言环境)中的月份名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 LocalDate ,其中包含日期2012-12-28,我想用本地化的月份名称(即12月份的波兰语)打印出来 in genitive 在波兰语中与主格不同( grudnia grudzień)。因为我也想使用自定义格式,我使用 DateTimeFormatterBuilder 创建了我自己的 DateTimeFormatter (哪种AFAIK是正确的方法)在Joda-Time):

I have LocalDate which contains date 2012-12-28 and I want to print it with localized month name (i.e. December in Polish) in genitive which in Polish is distinct from nominative (grudnia and grudzień respectively). Because I also want to use custom format I created my own DateTimeFormatter using DateTimeFormatterBuilder (which AFAIK is the right way to it in 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 并且有很多代码:

My question is about line marked with an arrow: how should I implement MonthNameGenitive? Currently it extends DateTimeFieldType and has quite much code:

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

}

看起来很邋and而不是防弹,因为我必须实现许多魔术方法,而且我正在使用 DelegatedDateTimeField 并且只覆盖一个方法( getAsText(ReadablePartial,Locale)),而其他名称相同:

Seems sloppy and not bullet-proof to me, since I had to implement many magic methods plus I'm using DelegatedDateTimeField and overriding only one method (getAsText(ReadablePartial, Locale)) while there are others with the same name:


  • getAsText(long,Locale)

  • getAsText(long)

  • getAsText(ReadablePartial,int,Locale)

  • getAsText(int,Locale )

  • getAsText(long, Locale)
  • getAsText(long)
  • getAsText(ReadablePartial, int, Locale)
  • getAsText(int, Locale)

是否有更好的方法来获得所需的输出(使用 DateTimeFormatter )或我的方法是否正确但非常详细?

Is there better approach to get desired output (using DateTimeFormatter) or my approach correct yet very verbose?

编辑:

我尝试使用新的JDK8 Time API(类似于基于JSR-310的Joda)实现相同的功能,并且可以轻松完成:

I've tried to achieve the same thing with new JDK8 Time API (which is similar to Joda, based on JSR-310) and it could be done easily:

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 使用自定义月份名称映射< Long,String> ,因此它非常易于使用。请参阅 DateTimeFormatterBuilder#appendText(TemporalField,Map)

where MONTH_NAMES_GENITIVE is Map<Long, String> with custom month names, so it's very easy to use. See DateTimeFormatterBuilder#appendText(TemporalField, Map).

有趣的是,在JDK8这整个波兰月 - 由于 DateFormatSymbols.getInstance(新的Locale(pl,PL))。getMonths()默认情况下返回genitive中的月份名称,因此不需要使用name-genitive play。 。虽然这个改变对我的用例是正确的(波兰语,我们说今天是2012年12月28日,使用月份名称),在其他一些情况下它可能很棘手(我们说它是十二月2012年使用主格并且它向后不兼容。

Interestingly, in JDK8 this whole Polish-month-name-genitive play is not necessary because DateFormatSymbols.getInstance(new Locale("pl", "PL")).getMonths() returns month names in genitive by default... While this change is correct for my use case (in Polish, we say "today is the 28th of December 2012" using month names in genitive), it can be tricky in some other cases (we say "it's December 2012" using nominative) and it's backwards incompatible.

推荐答案

你有我的同情 - Joda Time的现场系统有点复杂。

You have my sympathies - the field system in Joda Time is somewhat complicated.

但是,我建议在这种情况下最简单的方法实际上是使用 DateTimeFormatterBuilder.app结束(DateTimePrinter打印机)。请注意,如果您只对打印感兴趣,此方法有效 - 如果您还需要解析,生活会变得更复杂。

However, I suggest that in this case the simplest approach would actually be to use DateTimeFormatterBuilder.append(DateTimePrinter printer). Note that this approach will only work if you're only interested in printing - if you need to parse as well, life becomes more complicated.

此时你只需要实现 DateTimePrinter ,这是相对直截了当,特别是如果你很乐意忽略区域设置因为您只对单一文化感兴趣。您可以将所有逻辑(而不是它的大部分内容)放在一个方法中,并使其余的方法只委托给该方法。对于带有 long DateTimeZone 的重载,只需构造一个 DateTime 并调用 toLocalDateTime ,此时您可以委托其他方法。

At that point you only need to implement DateTimePrinter, which is relatively straightforward, particularly if you're happy to ignore the Locale as you're only interested in a single culture. You can put all the logic (not that there'll be much of it) in a single method, and make the rest of the methods just delegate to that method. For the overloads which take a long and a DateTimeZone, just construct a DateTime and call toLocalDateTime, at which point you can delegate to the other methods.

编辑:在事实上,如果您知道自己只关心本地值,那么可以选择编写一个抽象基类:

In fact, one option would be to write an abstract base class, if you knew you'd only care about the local values:

public abstract class SimpleDateTimePrinter implements DateTimePrinter {

    protected abstract String getText(ReadablePartial partial, Locale locale);

    @Override
    public void printTo(StringBuffer buf, long instant, Chronology chrono,
            int displayOffset, DateTimeZone displayZone, Locale locale) {
        DateTime dateTime = new DateTime(instant, chrono.withZone(displayZone));
        String text = getText(dateTime.toLocalDateTime(), locale);
        buf.append(text);
    }

    @Override
    public void printTo(Writer out, long instant, Chronology chrono,
            int displayOffset, DateTimeZone displayZone, Locale locale)
            throws IOException {
        DateTime dateTime = new DateTime(instant, chrono.withZone(displayZone));
        String text = getText(dateTime.toLocalDateTime(), locale);
        out.write(text);
    }

    @Override
    public void printTo(StringBuffer buf, ReadablePartial partial, Locale locale) {
        buf.append(getText(partial, locale));
    }

    @Override
    public void printTo(Writer out, ReadablePartial partial, Locale locale)
            throws IOException {
        out.write(getText(partial, locale));
    }
}

然后你可以轻松编写一个忽略了locale,只返回月份:

Then you can easily write a concrete subclass which ignores the locale, and just returns the month:

public class PolishGenitiveMonthPrinter extends SimpleDateTimePrinter {

    private static final ImmutableList<String> MONTH_NAMES =
            ImmutableList.of(
                "stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca",
                "lipca", "sierpnia", "września", "października", "listopada",
                "grudnia");

    private static final int MAX_MONTH_LENGTH;

    static {
        int max = 0;
        for (String month : MONTH_NAMES) {
            if (month.length() > max) {
                max = month.length();
            }
        }
        MAX_MONTH_LENGTH = max;
    }

    @Override
    public int estimatePrintedLength() {
        return MAX_MONTH_LENGTH;
    }

    @Override
    protected String getText(ReadablePartial partial, Locale locale) {
        int month = partial.get(DateTimeFieldType.monthOfYear());
        return MONTH_NAMES.get(month - 1);
    }
}

当然你可以在一个类中完成所有操作,但我可能会将其分解为使基类在将来更具可重用性。

Of course you could do this all in one class, but I'd probably break it out to make the base class more reusable in the future.

这篇关于使用Joda-Time DateTimeFormatter的genitive(波兰语语言环境)中的月份名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆