Odpowiedzi:
Jeśli używasz wersji Java starszej niż 8 ... możesz użyć Joda Time i PeriodFormatter. Jeśli naprawdę masz czas trwania (tj. Czas, który upłynął, bez odniesienia do systemu kalendarza), prawdopodobnie powinieneś używać Durationw większości - możesz wtedy zadzwonić toPeriod(określając cokolwiek PeriodTypechcesz, aby odzwierciedlić, czy 25 godzin stanie się 1 dzień i 1 godzinę lub nie itd.), Aby uzyskać plik, Periodktóry można sformatować.
Jeśli używasz Java 8 lub nowszej: zwykle sugeruję użycie java.time.Durationdo reprezentowania czasu trwania. Następnie możesz wywołać getSeconds()lub coś podobnego, aby uzyskać liczbę całkowitą do standardowego formatowania ciągu, zgodnie z odpowiedzią bobince, jeśli potrzebujesz - chociaż powinieneś uważać na sytuację, w której czas trwania jest ujemny, ponieważ prawdopodobnie chcesz mieć pojedynczy znak ujemny w ciągu wyjściowym . Więc coś takiego:
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;
}
Formatowanie w ten sposób jest dość proste, choć irytująco ręczne. W przypadku analizowania jest to ogólnie trudniejsze ... Jeśli chcesz, nadal możesz używać Joda Time nawet z Javą 8, jeśli chcesz.
Durationmetody S: duration.toHours(), duration.toMinutesPart()i duration.toSecondsPart()które są dostępne od Java 9. I aby uzyskać jedną wartość bezwzględna może używać duration.abs().
Jeśli nie chcesz przeciągać bibliotek, wystarczy samemu zrobić to za pomocą programu Formatter lub powiązanego skrótu, np. podana całkowita liczba sekund s:
String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
s/86400, (s%86400)/3600...na kilka dni, jeśli to konieczne ...
s > 86400 (jeden dzień): "\u221E"- nieskończoność
Używam DurationFormatUtils Apache common w następujący sposób:
DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
Jest to łatwiejsze, ponieważ Java 9. A Durationnadal nie jest formatowalna, ale dodawane są metody pobierania godzin, minut i sekund, co czyni zadanie nieco prostszym:
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);
Wynik tego fragmentu kodu to:
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"));przed użyciem formatfunkcji.
To może być trochę hakerskie, ale jest dobrym rozwiązaniem, jeśli ktoś chce to osiągnąć za pomocą 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)), Otrzymałem UnsupportedTemporalTypeException). Po prostu usunąłem kod, sprawdzając, czy różnica jest == 01. Pomyślałem, że jest 01to jakaś wartość maskująca, której nie do końca rozumiem, czy możesz to wyjaśnić?
isSupportedmetodę, zwraca informacje, jeśli istnieje prawidłowe pole do wyświetlenia w ciągu czytelnym dla człowieka. W każdym razie „maskowanie” w rzeczywistości nie jest maską. Kod pokazuje, że return value!=0lnie return value!=01. Następnym razem skorzystaj z opcji kopiuj-wklej.
TemporalAccessornie powinien być nadużywany przez określony czas. JSR-310 zaprojektował interfejs TemporalAmountdo tego celu.
Ldo oznaczania longwartości. Tak łatwo jest błędnie odczytać małe litery ldla cyfry 1, jak właśnie pokazano.
Oto jeszcze jeden przykład formatowania czasu trwania. Zauważ, że ta próbka pokazuje zarówno pozytywny, jak i negatywny czas trwania jako pozytywny czas trwania.
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());
}
}
Ta odpowiedź używa tylko Durationmetod i działa z Javą 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,");
}
A co z następującą funkcją, która zwraca + H: MM: SS lub + 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 );
}
}
Istnieje dość proste i eleganckie (IMO) podejście, przynajmniej przez okres krótszy niż 24 godziny:
DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))
Elementy formatujące potrzebują obiektu czasowego do sformatowania, więc możesz go utworzyć, dodając czas trwania do LocalTime równego 00:00 (tj. Północ). To da ci LocalTime reprezentujący czas trwania od północy do tego czasu, który można następnie łatwo sformatować w standardowej notacji GG: mm: ss. Ma to tę zaletę, że nie wymaga zewnętrznej biblioteki i do obliczeń używa biblioteki java.time zamiast ręcznego obliczania godzin, minut i sekund.
To działa opcja.
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;
}
Wywołaj metodę za pomocą
System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));
Produkuje coś takiego:
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();
}
używając tej funkcji
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));
}
Moja biblioteka Time4J oferuje rozwiązanie oparte na wzorcach (podobne do Apache DurationFormatUtils, ale bardziej elastyczne):
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
Ten kod demonstruje możliwości obsługi przepełnienia godzin i obsługi znaków, zobacz także interfejs API programu formatującego czas trwania oparty na wzorcu .
W scali (widziałem kilka innych prób i nie byłem pod wrażeniem):
def formatDuration(duration: Duration): String = {
import duration._ // get access to all the members ;)
f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}
Wygląda okropnie, tak? Cóż, dlatego używamy IDE do pisania tych rzeczy, aby wywołania metod ( $toHoursPartitp.) Miały inny kolor.
Jest f"..."to interpolator ciągów w stylu printf/ String.format(który umożliwia działanie $wstrzyknięcia kodu). Biorąc pod uwagę wynik 1 14:06:32.583, finterpolowany ciąg byłby równoważnyString.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)
W Scali, opierając się na rozwiązaniu YourBestBet, ale uproszczonym:
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
w scali, biblioteka nie jest potrzebna:
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("")
Nie widziałem tego, więc pomyślałem, że go dodam:
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));
Działa tylko przez 24 godziny, ale zwykle tego chcę.