Разбор LocalTime с високосной секундой
Я пытаюсь понять, как создать кастом DateTimeFormatter
для моего приложения. Мне в основном нужно обрабатывать время, которое написано так: "ЧЧММСС.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 ответа
Поскольку это имеет ограниченное применение для моих пользователей (редактирование неверного времени), я могу обработать этот особый случай, используя просто:
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
не может хранить информацию о високосной секунде, но выбрасывает ее. Вы можете только запросить синтаксический анализатор для возможного флага второй секунды. И тогда вам решать, что вы хотите делать с этой информацией.
Вывод: этот подход хорош для вас, если вы хотите игнорировать информацию о високосной секунде, но в противном случае допускаете ее при вводе.
Альтернативы:
Если вы действительно заинтересованы в разборе, проверке и оценке возможных високосных секунд, то я рекомендую использовать мою библиотеку 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.
Соответствующее описание из java.time.Instant JavaDoc:
[...] этот Java API определяет свою собственную временную шкалу, Java Time-Scale.
...
Реализации шкалы времени Java с использованием API-интерфейса JSR-310 не обязаны предоставлять какие-либо часы с точностью до одной секунды или монотонно или плавно. Поэтому реализациям не требуется фактически выполнять UTC-SLS или иначе знать о дополнительных секундах.
...
Шкала времени Java используется для всех классов даты и времени. Это включает в себя Instant, LocalDate, LocalTime, OffsetDateTime, ZonedDateTime и Duration.
Короче не стоит ожидать java.time
API, чтобы быть в курсе високосных секунд.
Обработка високосной секунды работает только для appendInstant
: см. DateTimeFormatter:parsedLeapSecond
Мгновенный анализ обрабатывает специальное время "високосного" 23:59:60. Дополнительные секунды происходят в 23:59:60 в часовом поясе UTC, но в другое местное время в других часовых поясах. Чтобы избежать этой потенциальной неоднозначности, обработка високосных секунд ограничена DateTimeFormatterBuilder.appendInstant (), так как этот метод всегда анализирует момент со смещением зоны UTC.