Форматирование продолжительности в Java 8/jsr310

Я перевожу проект с Joda-Time на собственные библиотеки времени java8 и столкнулся с проблемой.

Мне не удалось найти средство форматирования для Duration. Я хотел бы иметь собственный формат строки, например, ЧЧЧ+ММ, где продолжительность 75 часов и 15 минут будет форматироваться как "75+15".

Это было легко сделать с Joda-Time путем преобразования в период и использования PeriodFormatter, но я не смог найти этот тип класса в Java8. Я что-то упускаю?


person Chad Lowe    schedule 29.12.2013    source источник
comment
Возможный дубликат Как отформатировать продолжительность в java? (например, формат Ч:ММ:СС)   -  person Martin Schröder    schedule 08.01.2019
comment
@MartinSchröder Этот вопрос касается форматирования длительности (в любой форме), и, учитывая, что он предшествует Java 8, речь идет не конкретно о форматировании java.time.Duration. В этом вопросе ОП спрашивает, пропустил ли он существование средства форматирования в java.time для java.time.Duration. Таким образом, вопросы связаны, но не дублируются.   -  person Mark Rotteveel    schedule 08.01.2019
comment
для меня duration.get().toMillis() сработало. Я пытался просто duration.toMillis   -  person FBI Surveillance Van    schedule 29.03.2021


Ответы (5)


В jsr-310 нет средства форматирования периода/длительности, отличного от JodaTime. Не все функции JodaTime были перенесены в JSR-310 (например, не PeriodType). И, наоборот, JSR-310 имеет некоторые функции, недоступные в JodaTime (например, локализованные номера дней недели или подход с использованием шаблона стратегии с настройщиками).

Может случиться так, что в Java 9 будет введено какое-то встроенное форматирование точек (читайте что-нибудь об этом у С. Коулбурна).

Вывод: JSR-310 и JodaTime не полностью совместимы друг с другом, поэтому может потребоваться много работы. Я бы не был так заинтересован в миграции как можно скорее. Вам нужны специальные функции JSR-310, которых нет в JodaTime?

Дополнительное примечание: вам также следует помнить о том, что период joda (который включает в себя все единицы от лет до секунд) не полностью совместим с периодом jsr310 (только годы, месяцы, дни) или длительностью jsr310 (только часы, минуты, секунды и доли секунды).

person Meno Hochschild    schedule 29.12.2013
comment
Спасибо, думаю, мне просто придется свернуть свой собственный. Для меня это проект-хобби, так что это путешествие, а не пункт назначения. :) Даже если ему не хватает нескольких функций, я полагаю, что JSR-310 в конечном итоге будет иметь лучшую поддержку из коробки в других библиотеках, таких как jaxb . - person Chad Lowe; 29.12.2013
comment
Лично я вижу интеграцию jsr 310 с другими библиотеками не очень хорошо сделанной. Например, JAXB-интеграция невозможна в Java 8. Но есть обходные пути, такие как JodaTime, поэтому JAXB не является серьезным препятствием. - person Meno Hochschild; 29.12.2013
comment
@MenoHochschild Вы также можете получить количество дней, представленное длительностью (помимо часов, минут, секунд и нано). - person assylias; 29.12.2013
comment
@assylias Верно. Я упустил эту незначительную деталь. Но дело в том, что Duration в JSR-310 не принимает все единицы. И что еще хуже, из-за внутреннего преобразования только в секунды и нано, многие из единиц, которые разрешены в построении длительности, на самом деле не поддерживаются в запросах (или только беспорядочно - см. Ваш пример). Основная проблема заключается в том, что то, что вы вкладываете в Duration, не то, что вы получаете. - person Meno Hochschild; 29.12.2013

Java 9 и более поздние версии: Duration::to…Part методы

В Java 9 Duration класс получил новые to…Part метода для возврата различных частей дня, часы, минуты, секунды, миллисекунды/наносекунды. См. этот предварительный выпуск исходного кода OpenJDK.

Учитывая продолжительность 49Х30М20.123С…

  • toNanosPart() = 123000000
  • toMillisPart() = 123
  • toSecondsPart() = 20
  • toMinutesPart() = 30
  • toHoursPart() = 1
  • toDaysPart() = 2

Помните, что «дни» здесь означают куски по 24 часа, игнорируя даты в календаре. Если вам важны даты, используйте Period класс вместо этого.

Я не знаю, добавлены ли какие-либо дополнительные функции форматирования. Но, по крайней мере, вы сможете более удобно генерировать свои собственные строки из чисел, полученных с помощью этих новых методов получения.

Ява 8

Как ни странно, в первый выпуск java.time в Java 8 не было включено никаких удобных методов получения этих значений. Это одна из очень немногих упущений в превосходном дизайне фреймворка java.time.

См. соответствующий вопрос: Почему я не могу получить продолжительность в минутах или часах в java.time?.

person Basil Bourque    schedule 02.04.2016

Встроенного метода нет, но вы можете получить доступ к количеству часов/минут, не вычисляя их вручную. Ваш конкретный формат может выглядеть так:

Duration d = Duration.of(75, HOURS).plusMinutes(15);
long hours = d.toHours(); //75
long minutes = d.minusHours(hours).toMinutes(); //15
String HH_PLUS_MM = hours + "+" + minutes; //75+15
System.out.println(HH_PLUS_MM);

Если продолжительность гарантированно меньше 24 часов, вы также можете использовать этот трюк:

String hhPlusMm = LocalTime.MIDNIGHT.plus(d).format(DateTimeFormatter.ofPattern("HH+mm"));
person assylias    schedule 29.12.2013
comment
Как грязно запрашивать продолжительность, но это не ваша вина. Можно использовать часы и минуты в построении длительности, но нельзя использовать эти единицы непосредственно в стандартном методе get(TemporalUnit) :-( Я знаю, почему я разрабатываю свою собственную библиотеку времени. - person Meno Hochschild; 29.12.2013
comment
@MenoHochschild API хорошо подходит для использования Duration в качестве смещения DateTimes, но не в качестве отдельного объекта. Вы можете внести свой вклад в 310, если у вас есть идеи (хотя для Java 8 уже слишком поздно)! - person assylias; 29.12.2013
comment
@assylias Как вы импортировали TemporalUnit HOURS? - person IgorGanapolsky; 20.07.2015
comment
@ИгорьГанапольский import static java.time.temporal.ChronoUnit.HOURS; - person assylias; 20.07.2015

вы можете использовать DurationFormatUtils из commons-lang3-time (для минут нужно использовать "мм", так как формат такой же, как и в SimpleDateFormat): DurationFormatUtils.formatDuration(interval.toMillis(), "HHH+mm")

К сожалению, я не нашел способа исключить пустые части, так как в моем случае дни или часы могли быть равны 0, поэтому мне все равно пришлось накатывать свои собственные.

Обновление: я открыл проблему для этого на Apache commons.lang .time.DurationFormatUtils JIRA.

person Gregor    schedule 04.07.2017
comment
DurationFormatUtils.formatDurationWords можно использовать для исключения пустых полей. DurationFormatUtils.formatDurationWords(interval.toMillis(), true, true) - person wittyameta; 27.09.2018
comment
лучшее решение для использования на java 8, большое спасибо !!! - person Brendon Iwata; 23.07.2020

Я знаю, что это старый вопрос, но недавно я столкнулся с тем же. На самом деле должно быть лучшее решение, чем это, но это сработало для меня:

public static String millisToElapsedTime(long millis){
    DateFormat fmt = new SimpleDateFormat(":mm:ss.SSS");
    fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
    return (millis/3600000/*hours*/)+fmt.format(new Date(millis));
}

Затем вы можете добавить это:

public static String durationToElapsedTime(Duration d){
    return millisToElapsedTime(d.toMillis());
}
person CodeBlind    schedule 09.02.2016
comment
Здесь это регистрирует 12:00:00.022 в течение 22 мс. - person flup; 26.02.2016
comment
Извините за это - в строке SDF была ошибка - попробуйте вместо этого использовать заглавную HH. - person CodeBlind; 26.02.2016
comment
После дальнейших размышлений я понял, что все равно будет работать только до 24 часов. Я исправил это, чтобы позволить больше, чем просто 24 часа. - person CodeBlind; 26.02.2016