ISO 8601 Анализ интервала времени в Java
ISO 8601 определяет синтаксис представления временного интервала.
Существует четыре способа выражения временного интервала:
- Начало и конец, например "2007-03-01T13: 00: 00Z/2008-05-11T15: 30: 00Z"
- Начало и продолжительность, такие как "2007-03-01T13: 00: 00Z/P1Y2M10DT2H30M"
- Продолжительность и конец, например "P1Y2M10DT2H30M/2008-05-11T15: 30: 00Z"
- Только продолжительность, например "P1Y2M10DT2H30M", с дополнительной информацией о контексте
Если какие-либо элементы отсутствуют в конечном значении, они считаются такими же, как для начального значения, включая часовой пояс. Эта особенность стандарта позволяет получить краткие представления временных интервалов. Например, дата двухчасового собрания, включая время начала и окончания, может быть просто показана как "2007-12-14T13: 30/15: 30", где "/15: 30" означает "/2007-12- 14T15: 30" (на ту же дату, что и начало), или даты начала и окончания месячного расчетного периода как "2008-02-15/03-14", где "/03-14" подразумевает "/2008-03 -14" (в том же году, что и начало).
Кроме того, повторяющиеся интервалы формируются путем добавления "R [n]/" в начало интерпольного выражения, где R используется как сама буква, а [n] заменяется числом повторений. Оставляя значение для [n], означает неограниченное количество повторений. Итак, чтобы повторить интервал "P1Y2M10DT2H30M" пять раз, начиная с "2008-03-01T13: 00: 00Z", используйте "R5/2008-03-01T13: 00: 00Z/P1Y2M10DT2H30M".
Я ищу хороший Java-анализатор (если возможно, совместимый с библиотекой Joda-Time), чтобы проанализировать этот синтаксис. Любые указатели на хорошую библиотеку?
Ответы
Ответ 1
java.time
Структура java.time, встроенная в Java 8 и более поздняя версия, имеет метод Duration.parse
для синтаксического анализа длительность отформатированного ISO 8601:
java.time.Duration d = java.time.Duration.parse("PT1H2M34S");
System.out.println("Duration in seconds: " + d.get(java.time.temporal.ChronoUnit.SECONDS));
Печать Duration in seconds: 3754
Ответ 2
Для тех, кто в проекте, который может быть ограничен использованием сторонних библиотек (причины лицензирования или что-то еще), сама Java предоставляет хотя бы часть этой возможности, поскольку Java 1.6 (или ранее?), используя javax.xml.datatype.DatatypeFactory.newDuration(String) method и Duration. Метод DatatypeFactory.newDuration(String) будет анализировать строку в формате "PnYnMnDTnHnMnS". Эти классы предназначены для манипуляций с XML, но поскольку XML использует временные обозначения ISO 8601, они также служат удобными утилитами для синтаксического разбора.
Пример:
import javax.xml.datatype.*;
Duration dur = DatatypeFactory.newInstance().newDuration("PT5H12M36S");
int hours = dur.getHours(); // Should return 5
Я лично не использовал формат продолжительности, кроме 4-го, который вы перечисляете, поэтому я не могу ручаться за то, успешно ли он разбирает их или нет.
Ответ 3
Я так понимаю, вы уже пробовали Joda-Time? Подача строк примера из вашего вопроса через Interval.parse(Object)
показывает, что он может обрабатывать "начало и конец", "начало и продолжительность" и "продолжительность и конец", но не подразумеваемые поля и повторение.
2007-03-01T13:00:00Z/2008-05-11T15:30:00Z => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z
2007-03-01T13:00:00Z/P1Y2M10DT2H30M => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z
P1Y2M10DT2H30M/2008-05-11T15:30:00Z => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z
2007-12-14T13:30/15:30 => java.lang.IllegalArgumentException: Invalid format: "15:30" is malformed at ":30"
R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M => java.lang.IllegalArgumentException: Invalid format: "R5"
Единственная другая исчерпывающая библиотека даты/времени, о которой я знаю, JSR-310, которая, похоже, не обрабатывает такие интервалы.
На данный момент, создание ваших собственных улучшений поверх Joda-Time - это, вероятно, ваш лучший выбор, извините. Существуют ли какие-либо конкретные форматы интервала ISO, которые вам нужно обрабатывать, помимо тех, которые уже поддерживаются Joda-Time?
Ответ 4
Единственная библиотека, которая способна моделировать все функции анализа интервала, которые вы хотите, на самом деле является моей библиотекой Time4J (диапазон-модуль). Примеры:
// case 1 (start/end)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/2014-06-20T16:00Z"));
// output: [2012-01-01T14:15:00Z/2014-06-20T16:00:00Z)
// case 1 (with some elements missing at end component and different offset)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/08-11T16:00+00:01"));
// output: [2012-01-01T14:15:00Z/2012-08-11T15:59:00Z)
// case 1 (with missing date and offset at end component)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/16:00"));
// output: [2012-01-01T14:15:00Z/2012-01-01T16:00:00Z)
// case 2 (start/duration)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/P2DT1H45M"));
// output: [2012-01-01T14:15:00Z/2012-01-03T16:00:00Z)
// case 3 (duration/end)
System.out.println(MomentInterval.parseISO("P2DT1H45M/2012-01-01T14:15Z"));
// output: [2011-12-30T12:30:00Z/2012-01-01T14:15:00Z)
// case 4 (duration only, in standard ISO-format)
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P2DT1H45M");
// case 4 (duration only, in alternative representation)
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P0000-01-01T15:00");
System.out.println(isoDuration); // output: P1M1DT15H
Некоторые замечания:
-
Другие классы интервалов существуют с аналогичными возможностями синтаксического анализа, например DateInterval
или TimestampInterval
в пакете net.time4j.range.
-
Только для обработки продолжительности (которая может охватывать как календарные, так и часы), см. также javadoc. Существуют также функции форматирования, см. Вложенный класс Duration.Formatter
или локализованная версия net.time4j.PrettyTime
(на самом деле на 86 языках).
-
Взаимодействие предлагается с Java-8 (java.time
-package), но не с Joda-Time. Например: стартовый или конечный компонент MomentInterval
можно легко запросить с помощью getStartAsInstant()
или getEndAsInstant()
.
Повторяющиеся интервалы поддерживаются классом IsoRecurrence. Пример:
IsoRecurrence<MomentInterval> ir =
IsoRecurrence.parseMomentIntervals("R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M");
ir.intervalStream().forEach(System.out::println);
Вывод:
[2008-03-01T13:00:00Z/2009-05-11T15:30:00Z)
[2009-05-11T15:30:00Z/2010-07-21T18:00:00Z)
[2010-07-21T18:00:00Z/2011-10-01T20:30:00Z)
[2011-10-01T20:30:00Z/2012-12-11T23:00:00Z)
[2012-12-11T23:00:00Z/2014-02-22T01:30:00Z)