[英]Parsing LocalTime with leap second
我试图了解如何为我的应用程序构建自定义DateTimeFormatter
。 我基本上需要处理像“HHMMSS.FFFFFF”这样编写的时间。
我能够使用以下方法获得99%:
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
public static final DateTimeFormatter MY_TIME;
static {
MY_TIME = new DateTimeFormatterBuilder()
.appendValue(HOUR_OF_DAY, 2)
.appendValue(MINUTE_OF_HOUR, 2)
.optionalStart()
.appendValue(SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(MICRO_OF_SECOND, 0, 6, true)
.toFormatter().withResolverStyle(ResolverStyle.STRICT);
}
我可以很好地处理输入:
String text = "101530";
LocalTime lt = LocalTime.parse(text, MY_TIME);
甚至
String text = "070907.0705";
LocalTime lt = LocalTime.parse(text, MY_TIME);
和
String text = "0000";
LocalTime lt = LocalTime.parse(text, MY_TIME);
但由于某种原因,我无法理解用于处理闰秒的API,因此以下内容总是对我失败:
String text = "235960";
LocalTime lt = LocalTime.parse(text, MY_TIME);
我应该如何构建我的DateTimeFormatterBuilder
以便处理闰秒?
更新:我真的很喜欢ResolverStyle.STRICT
,因为它拒绝无效输入,例如:
所以我不能在这种情况下使用ResolverStyle.LENIENT
,我只想要闰秒的额外特殊情况。
闰秒处理仅适用于appendInstant
:请参阅DateTimeFormatter:parsedLeapSecond
即时解析处理'23:59:60'的特殊“闰秒”时间。 闰秒发生在UTC时区的'23:59:60',但是在不同时区的其他本地时间。 为了避免这种潜在的歧义, 闰秒的处理仅限于DateTimeFormatterBuilder.appendInstant() ,因为该方法始终使用UTC区域偏移量解析瞬间。
java.time.Instant JavaDoc中的相关描述:
[...]这个Java API定义了自己的时间尺度, Java Time-Scale 。
...
使用JSR-310 API实现Java时标不需要提供亚秒精确或单调或平滑进展的任何时钟。 因此,实现不需要实际执行UTC-SLS转换或以其他方式了解闰秒 。
...
Java时标用于所有日期时间类。 这包括Instant,LocalDate,LocalTime,OffsetDateTime,ZonedDateTime和Duration。
简而言之,您不应期望java.time
API能够java.time
闰秒。
如果没有显示日历日期和时区,显示闰秒的本地时钟时间也没有多大意义。 否则你不知道要解析的字符串是否真的有效( java.time
不会帮助你验证它)或者只是以宽松的方式(即解析“60”作为下一秒)。
java.time
的闰秒功能: java.time
确实会容忍任何虚拟日期与闰秒相结合,尽管在大多数情况下这是错误的。 并且DateTimeFormatter
仅接受UTC偏移零,但不接受“2012-07-01T08:59:60 + 0900”之类的表达式。
此外: java.time.Instant
无法存储闰秒信息,但会抛弃它。 您只能在解析器中查询可能的闰秒标志。 然后由您自己决定使用此信息。
结论:如果您想忽略闰秒信息但在输入中容忍它,则此方法适合您。
如果您真的对解析,验证和评估可能的闰秒感兴趣,那么我建议使用我的库Time4J 。 但它确实需要一个有效的日历日期(闰秒仅在极少数日期插入)。
ChronoFormatter<Moment> formatter =
ChronoFormatter.ofMomentPattern(
"uuuu-MM-dd'T'HH:mm:ss XXX",
PatternType.CLDR,
Locale.ROOT,
ZonalOffset.UTC
)
Moment m = formatter.parse("2012-07-01T08:59:60+09:00");
// this conversion throws away the leap second
Instant i = m.toTemporalAccessor();
有关更多信息,请参阅我在DZone上的文章。
由于这对我的用户使用有限(编辑无效时间),我可以使用以下简单处理这种特殊情况:
if (text.length() >= 6 && "60".equals(text.substring(4, 6))) {
String newText = text.substring(0, 4) + "59" + text.substring(6);
return LocalTime.parse(newText, MY_TIME);
}
return LocalTime.parse(text, MY_TIME);
这似乎是一个普遍接受的黑客:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.