3

在为某些日期助手编写单元测试时,我偶然发现了一种DateTimeFormatter我想了解如何解决的特定行为。

当输出年份 >9999 时,它总是在年份数字前添加一个加号。一些快速代码来说明这一点:

LocalDate localDate = LocalDate.of(9999, 1, 1);
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.set(9999, 0, 1, 12, 0 , 0);

// following assertion passes as both strings are "01-01-9999"
Assertions.assertEquals(
    new SimpleDateFormat("dd-MM-yyyy").format(cal.getTime()),
    localDate.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))
);


localDate = localDate.plusDays(365);
cal.add(Calendar.DAY_OF_MONTH, 365);

// following assertion passes (lengthy workaround using SimpleDateFormat)
Assertions.assertEquals(
    new SimpleDateFormat("dd-MM-yyyy").format(cal.getTime()),
    new SimpleDateFormat("dd-MM-yyyy").format(Timestamp.valueOf(localDate.atTime(LocalTime.MIDNIGHT)))
);

// following assertion fails:
// Expected : "01-01-10000"
// Actual   : "01-01-+10000"
Assertions.assertEquals(
    new SimpleDateFormat("dd-MM-yyyy").format(cal.getTime()),
    localDate.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))
);

现在,文档说明了年份模式:

如果字母数少于四个(但不是两个),则仅根据 SignStyle.NORMAL 输出负年份的符号。否则,如果超出焊盘宽度,则根据 SignStyle.EXCEEDS_PAD 输出符号。

所以这给出了一个提示,但我仍然一无所知:

如何使DateTimeFormatter输出与我的示例中的 Y10K+ 日期完全相同的字符串SimpleDateFormat.format()(= unsigned for positive years >9999)?

4

1 回答 1

3

ISO 8601 确实允许今年的格式。来自维基百科

为了表示 0000 之前或 9999 之后的年份,该标准还允许扩展年份表示,但只能通过发送方和接收方之间的事先协议。扩展的年份表示 [±YYYYY] 必须有超出四位数最小值的商定的额外年份数字,并且必须以 + 或 - 符号作为前缀,而不是更常见的 AD/BC(或 CE/BCE ) 符号;

但是,由于它只允许“通过发送方和接收方之间的事先约定”,因此添加符号是LocalDate.toString.

根据文档

年份:字母数决定了使用填充的最小字段宽度。如果字母数为两个,则使用简化的两位数形式。对于打印,这将输出最右边的两位数。对于解析,这将使用 2000 的基值进行解析,从而得到 2000 到 2099 范围内的年份。如果字母数少于四个(但不是两个),则符号仅在负年份输出SignStyle.NORMAL。否则,如果超出焊盘宽度,则按照SignStyle.EXCEEDS_PAD.

所以如果你不想要这个符号,你可以使用 3 个“y”,或者只使用 1 个“y”,因为 3 和 1 都是“小于四个(但不是两个)”。

此外,由于“y”表示“时代”,因此不会有任何负年份,因此您也不必担心它会输出负年份的符号。

例子:

System.out.println(
    LocalDate.of(10000, 1, 1)
        .format(DateTimeFormatter.ofPattern("dd-MM-yyy"))
); // 01-01-10000

appendValue(TemporalField, int, int, SignStyle)更一般地,您可以使用 中的方法指定标志样式DateTimeFormatterBuilder。您可以指定SignStyle.NEVER使其从不输出符号。

于 2021-09-22T02:11:00.517 回答