用闰秒解析LocalTime

时间:2017-12-28 15:12:22

标签: java datetime 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,因为它会拒绝无效输入,例如:

  • " 251213"或者,
  • " 126100"

所以我不能在这种情况下使用ResolverStyle.LENIENT,我只想要闰秒的额外特殊情况。

4 个答案:

答案 0 :(得分:2)

闰秒处理仅适用于appendInstant:请参阅DateTimeFormatter:parsedLeapSecond

  

即时解析处理'23:59:60'的特殊“闰秒”时间。   闰秒发生在UTC时区的'23:59:60',但在其他时间   不同时区的当地时间。为了避免这种潜力   模糊性,处理闰秒仅限于   DateTimeFormatterBuilder.appendInstant(),因为该方法总是解析   UTC区域偏移的瞬间。

答案 1 :(得分:1)

来自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了解闰秒。

答案 2 :(得分:1)

如果没有显示日历日期和时区,显示闰秒的本地时钟时间也没有多大意义。否则你不知道要解析的字符串是否真的有效(java.time - 包不会帮助你验证它)或者只是以宽松的方式(即解析“60”作为下一秒)

关于java.time的闰秒功能:

java.time确实会容忍任何虚拟日期与闰秒相结合,尽管在大多数情况下这是错误的。并且DateTimeFormatter仅接受UTC偏移零,但不接受“2012-07-01T08:59:60 + 0900”等表达式。

此外:java.time.Instant无法存储闰秒信息,但会将其丢弃。您只能query the parser获得可能的闰秒旗帜。然后由您自己决定使用此信息。

结论:如果您想忽略闰秒信息但在输入中容忍它,则此方法适合您。

备选方案:

如果您真的对解析,验证和评估可能的闰秒感兴趣,那么我建议使用我的库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上的文章。

答案 3 :(得分:0)

由于这对我的用户使用有限(编辑无效时间),我可以使用以下方式处理这种特殊情况:

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);

这似乎是一个普遍接受的黑客: