简体   繁体   English

用闰秒解析LocalTime

[英]Parsing LocalTime with leap second

I am trying to understand how to build a custom DateTimeFormatter for my application. 我试图了解如何为我的应用程序构建自定义DateTimeFormatter I basically need to handle time that are written like this "HHMMSS.FFFFFF" . 我基本上需要处理像“HHMMSS.FFFFFF”这样编写的时间。

I was able to get 99% of it using: 我能够使用以下方法获得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);
}

I can process inputs just fine: 我可以很好地处理输入:

String text = "101530";
LocalTime lt = LocalTime.parse(text, MY_TIME);

or even 甚至

String text = "070907.0705";
LocalTime lt = LocalTime.parse(text, MY_TIME);

and

String text = "0000";
LocalTime lt = LocalTime.parse(text, MY_TIME);

But for some reason I cannot make sense of the API for handling leap second so the following always fails for me: 但由于某种原因,我无法理解用于处理闰秒的API,因此以下内容总是对我失败:

String text = "235960";
LocalTime lt = LocalTime.parse(text, MY_TIME);

How should I build my DateTimeFormatterBuilder so that leap second is handled ? 我应该如何构建我的DateTimeFormatterBuilder以便处理闰秒?


Update: I really like the ResolverStyle.STRICT , since it reject invalid inputs such as: 更新:我真的很喜欢ResolverStyle.STRICT ,因为它拒绝无效输入,例如:

  • "251213" or, “251213”或
  • "126100" “126100”

So I cannot use ResolverStyle.LENIENT in this case, I simply want the extra special case for leap second. 所以我不能在这种情况下使用ResolverStyle.LENIENT ,我只想要闰秒的额外特殊情况。

Leap second handling only works for appendInstant : see DateTimeFormatter:parsedLeapSecond 闰秒处理仅适用于appendInstant :请参阅DateTimeFormatter:parsedLeapSecond

Instant parsing handles the special "leap second" time of '23:59:60'. 即时解析处理'23:59:60'的特殊“闰秒”时间。 Leap seconds occur at '23:59:60' in the UTC time-zone, but at other local times in different time-zones. 闰秒发生在UTC时区的'23:59:60',但是在不同时区的其他本地时间。 To avoid this potential ambiguity, the handling of leap-seconds is limited to DateTimeFormatterBuilder.appendInstant() , as that method always parses the instant with the UTC zone offset. 为了避免这种潜在的歧义, 闰秒处理仅限于DateTimeFormatterBuilder.appendInstant() ,因为该方法始终使用UTC区域偏移量解析瞬间。

Relevant description from java.time.Instant JavaDoc: java.time.Instant JavaDoc中的相关描述:

[...] this Java API defines its own time-scale, the Java Time-Scale . [...]这个Java API定义了自己的时间尺度, Java Time-Scale
... ...
Implementations of the Java time-scale using the JSR-310 API are not required to provide any clock that is sub-second accurate, or that progresses monotonically or smoothly. 使用JSR-310 API实现Java时标不需要提供亚秒精确或单调或平滑进展的任何时钟。 Implementations are therefore not required to actually perform the UTC-SLS slew or to otherwise be aware of leap seconds . 因此,实现不需要实际执行UTC-SLS转换或以其他方式了解闰秒
... ...
The Java time-scale is used for all date-time classes. Java时标用于所有日期时间类。 This includes Instant, LocalDate, LocalTime, OffsetDateTime, ZonedDateTime and Duration. 这包括Instant,LocalDate,LocalTime,OffsetDateTime,ZonedDateTime和Duration。

In short you should not expect java.time API to be aware of leap seconds. 简而言之,您不应期望java.time API能够java.time闰秒。

A local clock time showing leap second does not make much sense without also showing the calendar date and the timezone. 如果没有显示日历日期和时区,显示闰秒的本地时钟时间也没有多大意义。 Otherwise you don't know if the string to be parsed is really valid (the java.time -package will not help you to validate it) or is just meant in a lenient way (ie parsing "60" as next second). 否则你不知道要解析的字符串是否真的有效( java.time不会帮助你验证它)或者只是以宽松的方式(即解析“60”作为下一秒)。

About the leap second capabilities of java.time : 关于java.time的闰秒功能:

java.time would indeed tolerate any dummy date in combination with a leap second although this is wrong in most cases. java.time确实会容忍任何虚拟日期与闰秒相结合,尽管在大多数情况下这是错误的。 And the DateTimeFormatter only accepts the UTC-offset zero but not expressions like "2012-07-01T08:59:60+0900". 并且DateTimeFormatter仅接受UTC偏移零,但不接受“2012-07-01T08:59:60 + 0900”之类的表达式。

Furthermore: java.time.Instant cannot store the leap second information but throws it away. 此外: java.time.Instant无法存储闰秒信息,但会抛弃它。 You can only query the parser for a possible leap second flag. 您只能在解析器中查询可能的闰秒标志。 And then it is up to you what you want to do with this information. 然后由您自己决定使用此信息。

Conclusion: This approach is fine for you if you want to ignore the leap second information but otherwise tolerate it in input. 结论:如果您想忽略闰秒信息但在输入中容忍它,则此方法适合您。

Alternatives: 备择方案:

If you are really interested in parsing, validating and evaluating possible leap seconds then I recommend to use my library Time4J . 如果您真的对解析,验证和评估可能的闰秒感兴趣,那么我建议使用我的库Time4J But it does require a valid calendar date (leap seconds are inserted only on very few dates). 但它确实需要一个有效的日历日期(闰秒仅在极少数日期插入)。

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

For more informations, see also my article on DZone . 有关更多信息,请参阅我在DZone上的文章。

Since this is of limited use for my users (editing of invalid time), I can handle this special case using simply: 由于这对我的用户使用有限(编辑无效时间),我可以使用以下简单处理这种特殊情况:

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

It seems this is a generally accepted hack: 这似乎是一个普遍接受的黑客:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM