Я хотел бы отформатировать продолжительность в секундах, используя такой шаблон, как H: MM: SS. Текущие утилиты в java предназначены для форматирования времени, но не продолжительности.
Как отформатировать продолжительность в java? (например, формат H: MM: SS)
Ответы (20)
Если вы используете версию Java до 8 ... вы можете использовать Joda Time и _ 1_. Если у вас действительно есть продолжительность (т.е. истекшее количество времени, без ссылки на календарную систему), вам, вероятно, следует использовать Duration
по большей части - затем вы можете вызвать toPeriod
(указав то PeriodType
, которое вы хотите отразить, 25 часов превращаются в 1 день и 1 час или нет и т. Д.), Чтобы получить Period
, который вы можете отформатировать.
Если вы используете Java 8 или новее: обычно я предлагаю использовать java.time.Duration
для обозначения продолжительности. Затем вы можете вызвать getSeconds()
или тому подобное, чтобы получить целое число для стандартного форматирования строки в соответствии с ответом bobince, если вам нужно - хотя вы должны быть осторожны с ситуацией, когда продолжительность отрицательная, поскольку вам, вероятно, понадобится single em> отрицательный знак в выходной строке. Так что-то вроде:
public static String formatDuration(Duration duration) {
long seconds = duration.getSeconds();
long absSeconds = Math.abs(seconds);
String positive = String.format(
"%d:%02d:%02d",
absSeconds / 3600,
(absSeconds % 3600) / 60,
absSeconds % 60);
return seconds < 0 ? "-" + positive : positive;
}
Форматирование таким способом разумно просто, хотя и раздражает вручную. Для синтаксического анализа в целом становится сложнее ... Вы, конечно, можете использовать Joda Time даже с Java 8, если хотите.
java.time
замечательно, если вы не хотите форматировать длительности (действительно ли такая непонятная функция?), И в каком случае вам нужно иметь кучу непонятных применений joda-time? Я действительно надеюсь, что эта проблема будет решена до появления Java-9.
- person Groostav; 13.04.2015
Math.floorMod
и Math.floorDiv
вместо ручной отрицательной проверки.
- person Mark Jeronimus; 08.05.2018
Duration
s: duration.toHours()
, duration.toMinutesPart()
и duration.toSecondsPart()
, которые доступны начиная с Java 9. А для получения абсолютного значения можно использовать duration.abs()
.
- person recke96; 15.06.2018
Если вы не хотите перетаскивать библиотеки, достаточно просто сделать это самостоятельно, используя Formatter или связанный ярлык, например. заданное целое число секунд s:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
s/86400, (s%86400)/3600...
на несколько дней ...
- person bobince; 16.07.2011
s > 8640
0 (один день): "\u221E"
- бесконечность
- person QED; 24.08.2012
Я использую Apache common DurationFormatUtils вот так:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
Это стало проще, начиная с Java 9. A Duration
по-прежнему нельзя форматировать, но добавлены методы для получения часов, минут и секунд, что несколько упрощает задачу:
LocalDateTime start = LocalDateTime.of(2019, Month.JANUARY, 17, 15, 24, 12);
LocalDateTime end = LocalDateTime.of(2019, Month.JANUARY, 18, 15, 43, 33);
Duration diff = Duration.between(start, end);
String hms = String.format("%d:%02d:%02d",
diff.toHours(),
diff.toMinutesPart(),
diff.toSecondsPart());
System.out.println(hms);
Результат этого фрагмента:
24:19:21
Существует довольно простой и (IMO) элегантный подход, по крайней мере, для продолжительности менее 24 часов:
DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))
Форматировщикам требуется временный объект для форматирования, поэтому вы можете создать его, добавив длительность к LocalTime, равному 00:00 (т. Е. Полночь). Это даст вам LocalTime, представляющий продолжительность от полуночи до этого времени, который затем легко отформатировать в стандартной нотации ЧЧ: мм: сс. Это имеет то преимущество, что не требует внешней библиотеки и использует библиотеку java.time для расчета, а не вручную вычисляет часы, минуты и секунды.
Этот ответ использует только Duration
методы и работает с Java 8:
public static String format(Duration d) {
long days = d.toDays();
d = d.minusDays(days);
long hours = d.toHours();
d = d.minusHours(hours);
long minutes = d.toMinutes();
d = d.minusMinutes(minutes);
long seconds = d.getSeconds() ;
return
(days == 0?"":days+" jours,")+
(hours == 0?"":hours+" heures,")+
(minutes == 0?"":minutes+" minutes,")+
(seconds == 0?"":seconds+" secondes,");
}
Это может показаться хакерским, но это хорошее решение, если кто-то хочет добиться этого с помощью java.time
в Java 8:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.UnsupportedTemporalTypeException;
public class TemporalDuration implements TemporalAccessor {
private static final Temporal BASE_TEMPORAL = LocalDateTime.of(0, 1, 1, 0, 0);
private final Duration duration;
private final Temporal temporal;
public TemporalDuration(Duration duration) {
this.duration = duration;
this.temporal = duration.addTo(BASE_TEMPORAL);
}
@Override
public boolean isSupported(TemporalField field) {
if(!temporal.isSupported(field)) return false;
long value = temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
return value!=0L;
}
@Override
public long getLong(TemporalField field) {
if(!isSupported(field)) throw new UnsupportedTemporalTypeException(new StringBuilder().append(field.toString()).toString());
return temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
}
public Duration getDuration() {
return duration;
}
@Override
public String toString() {
return dtf.format(this);
}
private static final DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.optionalStart()//second
.optionalStart()//minute
.optionalStart()//hour
.optionalStart()//day
.optionalStart()//month
.optionalStart()//year
.appendValue(ChronoField.YEAR).appendLiteral(" Years ").optionalEnd()
.appendValue(ChronoField.MONTH_OF_YEAR).appendLiteral(" Months ").optionalEnd()
.appendValue(ChronoField.DAY_OF_MONTH).appendLiteral(" Days ").optionalEnd()
.appendValue(ChronoField.HOUR_OF_DAY).appendLiteral(" Hours ").optionalEnd()
.appendValue(ChronoField.MINUTE_OF_HOUR).appendLiteral(" Minutes ").optionalEnd()
.appendValue(ChronoField.SECOND_OF_MINUTE).appendLiteral(" Seconds").optionalEnd()
.toFormatter();
}
Duration.ofSeconds(20)
), я бы получил UnsupportedTemporalTypeException
). Я просто удалил код, проверяя, есть ли разница == 01
. Я подумал, что 01
было своего рода маскировкой, которую я не совсем понимаю, вы можете это объяснить?
- person Groostav; 13.04.2015
isSupported
, он возвращает информацию, если есть допустимое поле для отображения в читаемой человеком строке. В любом случае маскировка на самом деле не маска. Код показывает return value!=0l
, а не return value!=01
. Пожалуйста, в следующий раз воспользуйтесь копипастом.
- person MrJames; 08.11.2016
TemporalAccessor
не должен использоваться ненадлежащим образом в течение длительного времени. JSR-310 разработал интерфейс TemporalAmount
для этой цели.
- person Meno Hochschild; 04.01.2017
L
в верхнем регистре для обозначения long
значения. Как только что было продемонстрировано, очень легко неправильно интерпретировать строчные l
вместо цифры 1.
- person Ole V.V.; 06.05.2018
Вот еще один пример того, как отформатировать продолжительность. Обратите внимание, что этот образец показывает как положительную, так и отрицательную продолжительность как положительную.
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.SECONDS;
import java.time.Duration;
public class DurationSample {
public static void main(String[] args) {
//Let's say duration of 2days 3hours 12minutes and 46seconds
Duration d = Duration.ZERO.plus(2, DAYS).plus(3, HOURS).plus(12, MINUTES).plus(46, SECONDS);
//in case of negative duration
if(d.isNegative()) d = d.negated();
//format DAYS HOURS MINUTES SECONDS
System.out.printf("Total duration is %sdays %shrs %smin %ssec.\n", d.toDays(), d.toHours() % 24, d.toMinutes() % 60, d.getSeconds() % 60);
//or format HOURS MINUTES SECONDS
System.out.printf("Or total duration is %shrs %smin %sec.\n", d.toHours(), d.toMinutes() % 60, d.getSeconds() % 60);
//or format MINUTES SECONDS
System.out.printf("Or total duration is %smin %ssec.\n", d.toMinutes(), d.getSeconds() % 60);
//or format SECONDS only
System.out.printf("Or total duration is %ssec.\n", d.getSeconds());
}
}
Как насчет следующей функции, которая возвращает либо + H: MM: SS, либо + H: MM: SS.sss
public static String formatInterval(final long interval, boolean millisecs )
{
final long hr = TimeUnit.MILLISECONDS.toHours(interval);
final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
if( millisecs ) {
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
} else {
return String.format("%02d:%02d:%02d", hr, min, sec );
}
}
Это рабочий вариант.
public static String showDuration(LocalTime otherTime){
DateTimeFormatter df = DateTimeFormatter.ISO_LOCAL_TIME;
LocalTime now = LocalTime.now();
System.out.println("now: " + now);
System.out.println("otherTime: " + otherTime);
System.out.println("otherTime: " + otherTime.format(df));
Duration span = Duration.between(otherTime, now);
LocalTime fTime = LocalTime.ofNanoOfDay(span.toNanos());
String output = fTime.format(df);
System.out.println(output);
return output;
}
Вызовите метод с помощью
System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));
Производит что-то вроде:
otherTime: 09:30
otherTime: 09:30:00
11:31:27.463
11:31:27.463
Я не уверен, что вы хотите, но посмотрите этот вспомогательный класс Android
import android.text.format.DateUtils
Например: DateUtils.formatElapsedTime()
android date duration прошедшее время
Вы можете использовать java.time.Duration
, смоделированный на стандарты ISO-8601 и был представлен вместе с Java-8 как часть реализации JSR-310. В Java-9 было введено еще несколько удобных методов.
Демо:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;
public class Main {
public static void main(String[] args) {
LocalDateTime startDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 15, 20, 25);
LocalDateTime endDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 18, 24, 30);
Duration duration = Duration.between(startDateTime, endDateTime);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHours() % 24,
duration.toMinutes() % 60, duration.toSeconds() % 60);
System.out.println(formattedElapsedTime);
// ##############################################################################
// ####################################Java-9####################################
formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart());
System.out.println(formattedElapsedTime);
// ##############################################################################
}
}
Вывод:
PT3H4M5S
03:04:05
03:04:05
Узнайте о современном API даты и времени на странице Trail: Date Time а>.
- По любой причине, если вам нужно придерживаться Java 6 или Java 7, вы можете использовать ThreeTen-Backport, который поддерживает большую часть функций java.time для Java 6 и 7.
- Если вы работаете над проектом Android и ваш уровень API Android по-прежнему не соответствует Java-8, установите флажок API-интерфейсы Java 8+, доступные через удаление сахаров и Как использовать ThreeTenABP в Android Project.
Есть еще один способ сделать это для java8
public String formatDuration(Duration duration) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm.SSS");
return LocalTime.ofNanoOfDay(duration.toNanos()).format(formatter);
}
ofNanoOfDay
, _2 _... и почему LocalTime
. В контексте продолжительности это не имеет смысла: - \, но все же помогает.
- person t3chb0t; 28.01.2021
Duration
нужно преобразовать в LocalTime
, чтобы использовать свой format
метод. Что касается нано, они использовались для получения количества миллисекунд, но мы также можем написать что-то вроде LocalTime.ofSecondOfDay(duration.getSeconds()).format(formatter)
- person stanley; 31.01.2021
используя эту функцию
private static String strDuration(long duration) {
int ms, s, m, h, d;
double dec;
double time = duration * 1.0;
time = (time / 1000.0);
dec = time % 1;
time = time - dec;
ms = (int)(dec * 1000);
time = (time / 60.0);
dec = time % 1;
time = time - dec;
s = (int)(dec * 60);
time = (time / 60.0);
dec = time % 1;
time = time - dec;
m = (int)(dec * 60);
time = (time / 24.0);
dec = time % 1;
time = time - dec;
h = (int)(dec * 24);
d = (int)time;
return (String.format("%d d - %02d:%02d:%02d.%03d", d, h, m, s, ms));
}
Моя библиотека Time4J предлагает решение на основе шаблонов (аналогично Apache DurationFormatUtils
, но более гибкое):
Duration<ClockUnit> duration =
Duration.of(-573421, ClockUnit.SECONDS) // input in seconds only
.with(Duration.STD_CLOCK_PERIOD); // performs normalization to h:mm:ss-structure
String fs = Duration.formatter(ClockUnit.class, "+##h:mm:ss").format(duration);
System.out.println(fs); // output => -159:17:01
Этот код демонстрирует возможности обработки переполнения часов и обработки знаков, см. Также API длительности форматирования на основе шаблона.
В scala (видел и другие попытки, и не впечатлился):
def formatDuration(duration: Duration): String = {
import duration._ // get access to all the members ;)
f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}
Выглядит ужасно, да? Вот почему мы используем IDE для написания этого материала, чтобы вызовы методов ($toHoursPart
и т. Д.) Были другого цвета.
f"..."
- это строковый интерполятор в стиле _4 _ / _ 5_ (что позволяет использовать инъекцию кода $
). При выходе 1 14:06:32.583
интерполированная строка f
будет эквивалентна String.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)
Глядя на все эти вычисления, может быть полезно, что большинство единиц (часы, минуты и т. Д.) Имеют .toFooPart()
удобный метод.
E.g.
Duration.ofMinutes(110L).toMinutesPart() == 50
Чтение: количество минут, прошедших до следующего значения родительской единицы (час).
В Scala на основе решения YourBestBet, но в упрощенном виде:
def prettyDuration(seconds: Long): List[String] = seconds match {
case t if t < 60 => List(s"${t} seconds")
case t if t < 3600 => s"${t / 60} minutes" :: prettyDuration(t % 60)
case t if t < 3600*24 => s"${t / 3600} hours" :: prettyDuration(t % 3600)
case t => s"${t / (3600*24)} days" :: prettyDuration(t % (3600*24))
}
val dur = prettyDuration(12345).mkString(", ") // => 3 hours, 25 minutes, 45 seconds
в scala библиотека не нужна:
def prettyDuration(str:List[String],seconds:Long):List[String]={
seconds match {
case t if t < 60 => str:::List(s"${t} seconds")
case t if (t >= 60 && t< 3600 ) => List(s"${t / 60} minutes"):::prettyDuration(str, t%60)
case t if (t >= 3600 && t< 3600*24 ) => List(s"${t / 3600} hours"):::prettyDuration(str, t%3600)
case t if (t>= 3600*24 ) => List(s"${t / (3600*24)} days"):::prettyDuration(str, t%(3600*24))
}
}
val dur = prettyDuration(List.empty[String], 12345).mkString("")
sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));
перед использованием функции format
.
- person Rajish; 15.07.2011
DateFormat.getDateInstance()
.
- person Abhijit Sarkar; 25.07.2020
00:00:00.000
, когда количество часов достигнет 24 часов. Кроме того, отрицательная одна секунда форматируется как 23:59:59.000
.
- person V.S.; 12.08.2020