Ответы:
Если вы используете версию Java до 8 ... вы можете использовать Joda Time и PeriodFormatter. Если у вас действительно есть продолжительность (т. Е. Истекшее количество времени, без ссылки на систему календаря), то вам, вероятно, следует использовать Durationбольшую часть - вы можете позвонить toPeriod(указав все, что PeriodTypeвы хотите отразить, становится ли 25 часов 1 день и 1 час или нет, и т. Д.), Чтобы получить, Periodкоторый вы можете отформатировать.
Если вы используете Java 8 или более позднюю версию: я обычно рекомендую использовать java.time.Durationдля представления продолжительности. Затем вы можете вызвать getSeconds()или тому подобное, чтобы получить целое число для стандартного форматирования строки в соответствии с ответом bobince, если вам нужно - хотя вы должны быть осторожны с ситуацией, когда длительность отрицательна, так как вы, вероятно, хотите, чтобы в выходной строке был один отрицательный знак , Так что-то вроде:
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, если хотите, конечно.
Durationметоды S: duration.toHours(), duration.toMinutesPart()и duration.toSecondsPart()которые доступны с Java 9. И , чтобы получить абсолютное значение можно использовать duration.abs().
Если вы не хотите перетаскивать библиотеки, достаточно просто сделать это самостоятельно с помощью средства форматирования или связанного с ним ярлыка, например. заданное целое число секунд с:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
s/86400, (s%86400)/3600...несколько дней, если это необходимо ...
s > 86400 (один день): "\u221E"- бесконечность
Я использую Apuration DurationFormatUtils, например, так:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
Это проще, чем в Java 9. Функция по- 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
long duration = 4 * 60 * 60 * 1000;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
log.info("Duration: " + sdf.format(new Date(duration - TimeZone.getDefault().getRawOffset())));
sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));прежде чем использовать formatфункцию.
DateFormat.getDateInstance()вместо конкретных классов.
Это может быть отчасти хакерским, но это хорошее решение, если кто-то хочет сделать это с помощью Java 8 java.time:
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это какая-то маскирующая ценность, которую я не совсем понимаю, вы можете это объяснить?
isSupportedметода, он возвращает информацию, если есть допустимое поле для отображения в читаемой человеком строке. Во всяком случае, «маскировка» на самом деле не маска. Код показывает return value!=0lнет return value!=01. Пожалуйста, используйте copy-paste в следующий раз.
TemporalAccessorне должен использоваться не по назначению. JSR-310 разработал интерфейс TemporalAmountдля этой цели.
Lдля обозначения longзначения. Как легко lпродемонстрировать, неправильно прочитать строчную букву для цифры 1.
Вот еще один пример, как отформатировать продолжительность. Обратите внимание, что этот образец показывает как положительную, так и отрицательную продолжительность как положительную продолжительность.
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());
}
}
Этот ответ использует только 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,");
}
Это рабочий вариант.
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
Как насчет следующей функции, которая возвращает + 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 );
}
}
Существует довольно простой и (IMO) элегантный подход, по крайней мере, для продолжительности менее 24 часов:
DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))
Для форматирования нужен временный объект, так что вы можете создать его, добавив продолжительность к LocalTime 00:00 (т.е. полночь). Это даст вам LocalTime, представляющий продолжительность от полуночи до этого времени, которую затем легко отформатировать в стандартной записи HH: mm: ss. Преимущество этого заключается в том, что не требуется внешняя библиотека, и для вычисления используется библиотека java.time, а не часы, минуты и секунды вручную.
String duration(Temporal from, Temporal to) {
final StringBuilder builder = new StringBuilder();
for (ChronoUnit unit : new ChronoUnit[]{YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS}) {
long amount = unit.between(from, to);
if (amount == 0) {
continue;
}
builder.append(' ')
.append(amount)
.append(' ')
.append(unit.name().toLowerCase());
from = from.plus(amount, unit);
}
return builder.toString().trim();
}
используя эту функцию
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"..."Является printf/ String.formatстрокой стиля Интерполятор (что позволяет $инъекцию коды для работы) Учитывая выход 1 14:06:32.583, то fинтерполированная строка будет эквивалентнаString.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)
В 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("")
Я не видел этого, поэтому я решил добавить:
Date started=new Date();
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
task
long duration=new Date().getTime()-started.getTime();
System.out.println(format.format(new Date(duration));
Это работает только в течение 24 часов, но это то, что я обычно хочу на время.