使用 ThreeTen-Extra 解析 YearQuarter 时是否可以拒绝多个四分位数字?

Can multiple quarter digits be rejected when parsing a YearQuarter using ThreeTen-Extra?

我正在使用 YearQuarter from the ThreeTen-Extra 库来表示给定年份中的特定季度。

我使用的是自定义格式而不是默认格式,例如2018 年第三季度的“3Q2018”而不是“2018-Q3”。通过 YearQuarter.parse(text, formatter), I want values with leading zeros for the quarter to be rejected (via the standard DateTimeParseException).

解析值时

我的第一次尝试是使用 DateTimeFormatter.ofPattern("Q'Q'yy")。但是,这接受在四分之一前面有任意多个前导零的字符串。例如,“02Q2007”和“002Q2007”都不会被此格式化程序拒绝。

这似乎与其他时间类型的单字符模式处理方式一致。例如,这些成功解析没有错误:

YearMonth.parse("012-2018", DateTimeFormatter.ofPattern("M-yyyy"))
LocalTime.parse("001:00:01", DateTimeFormatter.ofPattern("H:mm:ss"))
LocalTime.parse("01:00:012", DateTimeFormatter.ofPattern("HH:mm:s"))

但是,这些拒绝输入 DateTimeParseException:

YearMonth.parse("012-2018", DateTimeFormatter.ofPattern("MM-yyyy"))
LocalTime.parse("001:00:01", DateTimeFormatter.ofPattern("HH:mm:ss"))
LocalTime.parse("01:00:012", DateTimeFormatter.ofPattern("HH:mm:ss"))

我如何构建一个 DateTimeFormatter 来以我想要的格式解析一个 YearQuarter,同时拒绝该季度超过一位数的值?理想情况下,我想将其作为模式字符串来执行,因为它们更易于人类阅读,并且更容易作为文本属性外化。

我还没有发现将此作为模式字符串执行此操作的方法,但以下内容将以编程方式构建具有所需格式的 DateTimeFormatter,拒绝以 0 填充的四分之一:

import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;

[...]

new DateTimeFormatterBuilder()
    .appendValue(IsoFields.QUARTER_OF_YEAR, 1)
    .appendLiteral('Q')
    .appendValue(ChronoField.YEAR, 4)
    .toFormatter();

如果您坚持使用模式字符串,那么我担心在 DateTimeFormatter 的上下文中没有办法,但我已经成功地测试了我的库 Time4J 是否提供了所需的行为:

    ChronoFormatter<CalendarQuarter> f =
        ChronoFormatter.ofPattern(
            "Q'Q'uuuu", PatternType.CLDR, Locale.ROOT, CalendarQuarter.chronology());
    CalendarQuarter cq = f.parse("3Q2018");
    System.out.println(cq); // 2018-Q3
    f.parse("13Q2018"); // exception
    f.parse("03Q2018"); // exception

CalendarQuarter 类型的对象对应 YearQuarter 所以你会发现类似的方法将其更改为公历日期,例如:

    CalendarQuarter cq = f.parse("3Q2018");
    LocalDate ld = cq.atEndOfQuarter().toTemporalAccessor();
    System.out.println(ld); // 2018-09-30