Java DateTimeFormatter:仅在非 0 时将毫秒打印到 3 个位置
Java DateTimeFormatter: Print milliseconds to 3 places only if not 0
我正在尝试做一些看似很简单的事情,但我终其一生都无法让它发挥作用。
我想将某些字符串解析为 LocalTime,然后以所需的格式打印它们。我想要的是:
- 始终至少打印
HH:mm:ss
(13:00:00
打印为 13:00:00
)。
- 仅在 != 0 时打印毫秒(
13:45:20
和 13:45:20.000
都打印为 13:45:20
)
- 如果打印毫秒,总是将它们打印到三个地方。 (
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
所以你不能覆盖实现)。相反,我可以建议两个选项:
- 始终显示小数点后 3 位,然后 运行
.replace(".000", "")
,或
- 如果时间戳为零(即设置为
null
),则移除时间戳的毫秒部分
我正在尝试做一些看似很简单的事情,但我终其一生都无法让它发挥作用。
我想将某些字符串解析为 LocalTime,然后以所需的格式打印它们。我想要的是:
- 始终至少打印
HH:mm:ss
(13:00:00
打印为13:00:00
)。 - 仅在 != 0 时打印毫秒(
13:45:20
和13:45:20.000
都打印为13:45:20
) - 如果打印毫秒,总是将它们打印到三个地方。 (
13:45:20.01
打印为13:45:20.010
)
根据 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.
然而,强制 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
所以你不能覆盖实现)。相反,我可以建议两个选项:
- 始终显示小数点后 3 位,然后 运行
.replace(".000", "")
,或 - 如果时间戳为零(即设置为
null
),则移除时间戳的毫秒部分