Відповіді:
Якщо ви використовуєте версію 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 > 8640
0 (один день): "\u221E"
- нескінченність
Я використовую таким чином DurationFormatUtils Apache common так:
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
функцію.
Це може бути певним хакі, але це хороше рішення, якщо хтось намагається досягти цього за допомогою 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
. Будь ласка, використовуйте копіювальну пасту наступного разу.
TemporalAccessor
не повинен використовуватися для тривалості. TemporalAmount
Для цієї мети JSR-310 розробив інтерфейс .
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,");
}
Як щодо наступної функції, яка повертає або + 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 для обчислення, а не вручну обчислювати години, хвилини та секунди.
Це робочий варіант.
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
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
в масштабі, бібліотека не потрібна:
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 годин, але я зазвичай хочу цього тривати.