Java DateTimeFormatter:仅在非 0 时将毫秒打印到 3 个位置

Java DateTimeFormatter: Print milliseconds to 3 places only if not 0

我正在尝试做一些看似很简单的事情,但我终其一生都无法让它发挥作用。

我想将某些字符串解析为 LocalTime,然后以所需的格式打印它们。我想要的是:

  1. 始终至少打印 HH:mm:ss13:00:00 打印为 13:00:00)。
  2. 仅在 != 0 时打印毫秒(13:45:2013:45:20.000 都打印为 13:45:20
  3. 如果打印毫秒,总是将它们打印到三个地方。 (13:45:20.01 打印为 13:45:20.010

根据 optionalStart:

的文档,似乎应该可以在 DateTimeFormatter 中使用可选值
All elements in the optional section are treated as optional.
During formatting, the section is only output if data is available in the
{@code TemporalAccessor} for all the elements in the section.
During parsing, the whole section may be missing from the parsed string.

然而,强制 3 位小数位的 millis 似乎绕过了可选方面,即 .000 在 millis == 0 时打印:

final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2)
            .appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .optionalStart()
            .appendLiteral('.')
            .appendValue(MILLI_OF_SECOND, 3)
            .toFormatter();

System.out.println(formatter.format(LocalTime.parse("12:45:00"))); // Outputs 12:45:00.000, bad!
System.out.println(formatter.format(LocalTime.parse("12:45:00.000"))); // Outputs 12:45:00.000, bad!
System.out.println(formatter.format(LocalTime.parse("12:45:00.010")));  // Outputs 12:45:00.010, good!

当然可以通过条件来完成,手动检查是否 millis != 0,但我想知道这是否可以通过不太明确的方式实现。

非常感谢!

困惑在于 optionalStart 的行为。您希望它 t运行cate 为零的毫秒值(因为您认为毫秒值不存在)。但是,optionalStart 只查看日期时间组件的存在,而不查看值(因此时间的毫秒组件的 "existance" 永远不会丢失)。将其视为没有毫秒的时间戳与零毫秒的时间戳之间的区别。

DateTimeFormatterBuilder.appendValue 未声明对 运行 小数位进行分类(https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatterBuilder.html#appendValue-java.time.temporal.TemporalField-int-), so to get the behaviour you seek, use https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatterBuilder.html#appendFraction-java.time.temporal.TemporalField-int-int-boolean-,例如

final DateTimeFormatter formatter = new DateTimeFormatterBuilder() 
.appendValue(HOUR_OF_DAY, 2) 
.appendLiteral(':') 
.appendValue(MINUTE_OF_HOUR, 2) 
.appendLiteral(':') 
.appendValue(SECOND_OF_MINUTE, 2) 
.optionalStart() 
.appendFraction(MILLI_OF_SECOND, 0, 3, true) 
.toFormatter();

注意:您将小数位添加为文字,这意味着格式化程序无法理解您希望将毫秒作为分数。通常,如果您想将值视为分数而不是整数,则库必须提供小数位。

编辑: 向@AMterp 道歉,因为它与预期的行为不完全匹配。具体来说,除非毫秒分量为零,否则应显示 3 位小数。

要实现这一点,不幸的是我看不到让 java.time.DateTimeFormatter 以这种方式运行的方法(内置函数的 none 支持这个并且 class 是 final 所以你不能覆盖实现)。相反,我可以建议两个选项:

  1. 始终显示小数点后 3 位,然后 运行 .replace(".000", ""),或
  2. 如果时间戳为零(即设置为 null),则移除时间戳的毫秒部分