Добавьте продолжительность к моменту, используя time4j
Поскольку я конвертирую код с использованием реализации java.time в time4j, я хочу добавить Duration
к Moment
но я получаю ошибку компиляции. В java.time я бы сделал следующее:
val startTime: ZonedDateTime = ...
val duration: TemporalAmount = ...
val endTime: ZonedDateTime = startTime.plus(duration)
Однако используя time4j, то же самое не работает:
val startTime: Moment = ...
val duration: Duration[ClockUnit] = ...
val endTime: Moment = startTime.plus(duration)
Компилятор жалуется на общее взаимодействие между Duration
и Moment
, Независимо от того, каким образом я создаю Duration
(по крайней мере, что я нашел), это должно было бы иметь связанный родовой java.util.concurrent.TimeUnit
, так как Moment
инвентарь TimePoint[java.util.concurrent.TimeUnit]
и Moment#plus
Метод, следовательно, нуждается в Duration[java.util.concurrent.TimeUnit]
с тем же связанным родовым Moment
за единицу времени.
Меня это удивляет java.util.concurrent.TimeUnit
используется, поскольку это не тип time4j. Я упускаю более мелкие детали вокруг этого выбора? У меня сложилось впечатление, что это было решено дизайном.
Один способ, который работает, если я использую PlainTimestamp
и добавляет Duration[ClockUnit | CalendarUnit | IsoUnit]
, как реализует первый тип TimePoint[IsoUnit, PlainTime]
и перегружает дополнительные поддерживаемые блоки. Тогда я могу преобразовать PlainTimestamp
в какой часовой пояс мне нужно позже. Это предполагаемый дизайн?
(И все же:) Как правильно Duration
тип для использования с Moment.plus
метод?
Я использую time4j версии 4.27.2
1 ответ
Краткий ответ как мигрировать zonedDateTime.plus(Duration.ofHours(24))
:
Moment.from(zonedDateTime.toInstant()).plus(MachineTime.of(24, TimeUnit.HOURS));
См. Также API глобального типа продолжительности MachineTime.
Длинный ответ подробно:
В отличие от java.time
-API, который знает только один единственный класс ChronoUnit для представления наиболее часто используемых временных единиц, применимых к произвольным временным объектам (и общий интерфейс TemporalUnit
), единица измерения и длительность библиотеки Time4J гораздо более детализированы.
- Каждый календарь или временный тип с временной шкалой имеет свой собственный тип единиц измерения, который также четко характеризует временную шкалу временного типа, поэтому даже компилятор скажет вам не смешивать различные типы единиц разных сущностей, таких как
Moment
(аналогjava.time.Instant
) или жеPlainTimestamp
(аналогLocalDateTime
). - Это различие кодируется по замыслу как параметр универсального типа U в суперклассе TimePoint. Для конкретных классов:
Moment
работает в основном сjava.util.concurrent.TimeUnit
в то время какPlainTimestamp
работает с любой реализациейIsoUnit
особенно с перечислениямиCalendarUnit
а такжеClockUnit
, - Обобщенная концепция продолжительности описывается интерфейсом TimeSpan, который также задается типом единицы U, который будет использоваться. Вы можете добавить временной интервал к моменту, только если тип устройства
java.util.concurrent.TimeUnit
, Это предлагается специальным классом реализацииMachineTime
, Кроме того, другая продолжительность реализации, называемаяnet.time4j.Duration
совместим только с локальными типами, такими какPlainTimestamp
, - Специальные временные объекты имеют свои собственные наборы подходящих единиц. Например, единица для эры существует только в японском календаре, но не для других календарей, которые имеют либо ноль, одну или только две эры.
Почему разные типы юнитов для Moment
а также PlainTimestamp
?
Частично на это уже отвечает последний пункт о подходящих наборах единиц. Например, месяцы и годы не имеют большого смысла для машиноподобных типов, так как Moment
, Поэтому выбранное перечисление java.util.concurrent.TimeUnit
охватывает то, что необходимо в качестве единиц для Moment
,
Кроме того, различные типы юнитов Time4J помогают дифференцироваться. net.time4j.Duration<ClockUnit>
рассчитывается в местном контексте, в то время как MachineTime<TimeUnit>
рассчитывается как глобальная продолжительность Это относится не только к единицам, связанным с часами, таким как часы, но и к календарным единицам. Год это не просто год. У нас есть ISO-календарные годы (соответствующие григорианским годам). У нас есть ISO-неделя-год (продолжительность 364 или 371 дней). У нас есть исламские годы (354 или 355 дней) и так далее. Поэтому Time4J знает много разных календарных единиц (следите за API календарного модуля). Таким образом, Time4J, наконец, принял дизайн, предотвращающий сравнение длительностей с различными типами юнитов (что будет похоже на сравнение яблок и апельсинов).
Следующий пример для редкого случая изменения международной даты в Самоа (2011-12-30 был пропущен) демонстрирует, насколько важным может быть различие типов единиц:
В Time4J мы просто используем различные типы единиц для выражения, если арифметика происходит на локальной или глобальной временной шкале. Вывод: в Java-8 мы должны тщательно изучить контекст, в Time4J типы модулей дают ценную дополнительную информацию.
ZonedDateTime zdt = ZonedDateTime.of(2011, 12, 29, 0, 0, 0, 0, "Pacific/Apia");
Moment m1 = Moment.from(zdt.toInstant());
Moment m2 = m1.plus(MachineTime.of(24, TimeUnit.HOURS));
assertThat(m2.isSimultaneous(m1.plus(MachineTime.of(1, TimeUnit.DAYS))), is(true));
System.out.println(m2); // 2011-12-30T10:00:00Z
System.out.println(m2.toZonalTimestamp(PACIFIC.APIA)); // 2011-12-31T00
System.out.println(m1.toZonalTimestamp(PACIFIC.APIA).plus(2, CalendarUnit.DAYS)); // 2011-12-31T00
Объекты TimeUnit.DAYS
а также CalendarUnit.DAYS
очевидно, не то же самое. Они требуют даже разных количеств (1 против 2), чтобы получить одинаковые результаты.
Примечание:
Теперь я сократил первую версию своего ответа - в основном не упомянув о материалах, связанных с Java-8, потому что я думаю, что можно легко написать слишком много о теме создания модулей / продолжительности в узком контексте вашего вопроса (и Я даже не дал какого-либо полного ответа). Страница учебного пособия или дополнительная страница документации, как здесь, на SO, будет действительно лучшим местом.
Но по крайней мере два других пункта, не упомянутых в моем ответе, могут быть вам интересны (net.time4j.Duration
): Обработка знаков и специализированная метрика часового пояса. Последний даже может быть альтернативой MachineTime
в некоторых случаях.