Java DateTimeFormatter:仅在不为0的情况下将毫秒数打印到3个位置

AMT*_*erp 3 java java-8 java-time

我正在尝试做一些看似很简单的事情,但是我一生无法使它正常工作。

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

  1. 始终至少打印HH:mm:ss13:00:00打印为13:00:00)。
  2. 如果它们= 0仅打印毫秒(13:45:20并且13:45:20.000两个都打印为13:45:20
  3. 如果打印毫秒,请始终将它们打印到三个位置。(13:45:20.01打印为13:45:20.010

根据以下文档,似乎可以在DateTimeFormatter中使用可选选项optionalStart

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.
Run Code Online (Sandbox Code Playgroud)

但是,强制将Millis保留为小数点后3位似乎绕过了可选方面,即.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!
Run Code Online (Sandbox Code Playgroud)

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

谢谢堆!

Woo*_*odz 5

混乱在于行为optionalStart。您期望它截断零毫秒值(因为您认为毫秒值不存在)。但是,optionalStart仅查看日期时间分量的存在,而不是值(因此,永远不会丢失时间的毫秒分量的“存在”)。可以将其视为没有毫秒的时间戳与具有零毫秒的时间戳之间的差异。

DateTimeFormatterBuilder.appendValue不声称截断小数点(https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatterBuilder.html#appendValue-java.time.temporal.TemporalField-int-),为了获得您想要的行为,请使用https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatterBuilder.html#appendFraction-java.time.temporal.TemporalField-int-int -布尔值-,例如

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();
Run Code Online (Sandbox Code Playgroud)

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

编辑: 抱歉@AMterp不太符合预期的行为。具体来说,除非毫秒部分为零,否则应显示3个小数位。

为了实现这一点,不幸的是,我看不到一种java.time.DateTimeFormatter以这种方式表现的方法(没有内置函数支持该方法,而该类是内置的,final因此您无法覆盖实现)。相反,我可以建议两个选择:

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