用闰秒解析 LocalTime
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
,因为它拒绝无效输入,例如:
- “251213”或者,
- “126100”
所以在这种情况下我不能使用 ResolverStyle.LENIENT
,我只是想要闰秒的额外特例。
闰秒处理仅适用于 appendInstant
:参见 DateTimeFormatter:parsedLeapSecond
Instant parsing handles the special "leap second" time of '23:59:60'.
Leap seconds occur at '23:59:60' in the UTC time-zone, but at other
local times in different time-zones. 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.
来自java.time.Instant JavaDoc的相关描述:
[...] this Java API defines its own time-scale, the 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.
Implementations are therefore not required to actually perform
the UTC-SLS slew or to otherwise be aware of leap seconds.
...
The Java time-scale is used for all date-time classes. This includes Instant, LocalDate, LocalTime, OffsetDateTime, ZonedDateTime and Duration.
简而言之,您不应该期望 java.time
API 知道闰秒。
由于这对我的用户来说用途有限(编辑无效时间),我可以简单地处理这种特殊情况:
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);
这似乎是一个普遍接受的技巧:
如果不同时显示日历日期和时区,则显示闰秒的本地时钟时间没有多大意义。否则你不知道要解析的字符串是否真的有效(java.time
-package 不会帮助你验证它)或者只是以一种宽松的方式(即下一秒解析“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 上的文章。
我想了解如何为我的应用程序构建自定义 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
,我只是想要闰秒的额外特例。
闰秒处理仅适用于 appendInstant
:参见 DateTimeFormatter:parsedLeapSecond
Instant parsing handles the special "leap second" time of '23:59:60'. Leap seconds occur at '23:59:60' in the UTC time-zone, but at other local times in different time-zones. 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.
来自java.time.Instant JavaDoc的相关描述:
[...] this Java API defines its own time-scale, the 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. Implementations are therefore not required to actually perform the UTC-SLS slew or to otherwise be aware of leap seconds.
...
The Java time-scale is used for all date-time classes. This includes Instant, LocalDate, LocalTime, OffsetDateTime, ZonedDateTime and Duration.
简而言之,您不应该期望 java.time
API 知道闰秒。
由于这对我的用户来说用途有限(编辑无效时间),我可以简单地处理这种特殊情况:
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);
这似乎是一个普遍接受的技巧:
如果不同时显示日历日期和时区,则显示闰秒的本地时钟时间没有多大意义。否则你不知道要解析的字符串是否真的有效(java.time
-package 不会帮助你验证它)或者只是以一种宽松的方式(即下一秒解析“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 上的文章。