Do Twojej wiadomości, format, który zdaje się opisywać, jest Durationzdefiniowany w rozsądnym standardzie ISO 8601 : PnYnMnDTnHnMnSgdzie Poznacza „Okres” i oznacza początek, Toddziela część daty od części czasu, a pomiędzy nimi są opcjonalne wystąpienia liczby z pojedynczym -skrót liter. Na przykład PT4H30M= cztery i pół godziny.
Basil Bourque
1
Jeśli wszystko inne zawiedzie, zrób to sam. Wystarczy użyć kolejnych aplikacji %i /podzielić numer na części. Niemal łatwiejsze niż niektóre z proponowanych odpowiedzi.
Hot Licks,
@HotLicks Pozostaw to metodom bibliotecznym, aby uzyskać znacznie czystszy i bardziej przejrzysty kod niż używanie /i %.
Ole VV
Tak, w ciągu ostatnich 8 lat, odkąd zadałem to pytanie (!) Przeniosłem się do czasu joda, który bardzo dobrze pasuje do mojego przypadku użycia
phatmanace
@phatmanace Projekt Joda-Time jest teraz w trybie konserwacji i zaleca migrację do klas java.time wbudowanych w Javę 8 lub nowszą.
Z poniższej odpowiedzi wynika, że instancję Period można utworzyć bezpośrednio, bez uprzedniego tworzenia instancji Duration, a następnie konwertowania jej na Period. Np. Okres okresu = nowy okres (milis); Ciąg sformatowany = formatter.print (kropka);
Basil Vandegriend
7
Uważaj na konwersję „duration.toPeriod ()”. Jeśli czas trwania jest dość długi, część dzienna pozostanie równa 0. Część godzinowa będzie rosła. Dostaniesz 25h10m23s, ale nigdy nie dostaniesz „d”. Powodem jest to, że nie ma w pełni poprawnego sposobu przeliczania godzin na dni w ścisły sposób Jody. W większości przypadków, jeśli porównujesz dwa momenty i chcesz je wydrukować, możesz wykonać nowy okres (t1, t2) zamiast nowego czasu trwania (t1, t2) .toPeriod ().
Boon
@Boon Czy wiesz, jak przekonwertować czas trwania na okres w odniesieniu do dni? Używam czasu, od którego mogę zastąpić sekundę w moim zegarze. Ustawienie wydarzenia PeriodType.daysTime()lub .standard()nie pomogło
murt
4
@murt Jeśli naprawdę chcesz i akceptujesz standardową definicję dnia, możesz w powyższym kodzie wpisać „formatter.print (duration.toPeriod (). normalizedStandard ())”. Baw się dobrze!
Nigdy nie powinieneś polegać na wynikach funkcji toStrong (), ponieważ może to ulec zmianie w kolejnych wersjach.
Weltraumschaf
14
@Weltraumschaf to raczej się nie zmieni, ponieważ jest określone w javadoc
aditsu zakończyło pracę, ponieważ SE jest ZŁEM.
9
@Weltraumschaf Jest mało prawdopodobne, aby się zmieniło, ponieważ dane wyjściowe Duration::toStringsą sformatowane zgodnie z dobrze zdefiniowaną i znaną normą ISO 8601 .
Basil Bourque
1
Jeśli nie chcesz ułamków, dodaj .replaceAll("\\.\\d+", "")przed wywołaniem toLowerCase().
zb226
1
@Weltraumschaf Twój punkt widzenia jest ogólnie poprawny i sam nie polegałbym na wynikach metody toString () większości klas. Ale w tym bardzo szczególnym przypadku definicja metody stwierdza, że jej dane wyjściowe są zgodne ze standardem ISO-8601, jak widać w Javadoc metody . Więc nie jest to szczegół implementacji, jak w większości klas, dlatego nie spodziewałbym się, że język tak dojrzały jak Java zmieni się w ten sposób,
lucasls
13
Apache commons-lang zapewnia użyteczną klasę do wykonania tego zadania DurationFormatUtils
Projekt ThreeTen-Extra , który jest prowadzony przez Stephena Colebourne'a, autora JSR 310, java.time i Joda-Time , ma AmountFormatsklasę, która współpracuje ze standardowymi klasami daty i czasu Java 8. Jest jednak dość rozwlekły, bez opcji na bardziej kompaktowe wyjście.
Duration d = Duration.ofMinutes(1).plusSeconds(9).plusMillis(86);
System.out.println(AmountFormats.wordBased(d, Locale.getDefault()));
Wow, miło wiedzieć, nie widziałem tej funkcji. Ma jednak jedną poważną wadę: brak przecinka oksfordzkiego .
Basil Bourque
4
@BasilBourque Przecinek oksfordzki jest typowy dla Stanów Zjednoczonych, ale co ciekawe, nie dla Wielkiej Brytanii. Moja biblioteka Time4J (która ma znacznie lepszą internacjonalizację) obsługuje to rozróżnienie w klasie net.time4j.PrettyTime, a także umożliwia kontrolę nad kompaktowym wyjściem, jeśli jest to pożądane.
Alternatywą dla podejścia konstruktora w Joda-Time byłoby rozwiązanie oparte na wzorcach . To jest oferowane przez moją bibliotekę Time4J . Przykład użycia klasy Duration.Formatter (dodano kilka spacji dla większej czytelności - usunięcie spacji da pożądany styl C #):
IsoUnit unit = ClockUnit.MILLIS;
Duration<IsoUnit> dur = // normalized duration with multiple components
Duration.of(123456, unit).with(Duration.STD_PERIOD);
Duration.Formatter<IsoUnit> f = // create formatter/parser with optional millis
Duration.Formatter.ofPattern("D'd' h'h' m'm' s[.fff]'s'");
System.out.println(f.format(dur)); // output: 0d 0h 2m 3.456s
Ten program formatujący może również drukować czasy trwania java.time-API (jednak funkcje normalizacji tego typu są mniej wydajne):
Oczekiwanie OP, że „123456 ms jako długość zostanie wydrukowane jako 4d1h3m5s” jest obliczane w oczywiście nieprawidłowy sposób. Za powód przyjmuję niechlujstwo. Ten sam program formatujący czas trwania zdefiniowany powyżej może być również używany jako parser. Poniższy kod pokazuje, że „4d1h3m5s” odpowiada raczej 349385000 = 1000 * (4 * 86400 + 1 * 3600 + 3 * 60 + 5):
Innym sposobem jest użycie klasy net.time4j.PrettyTime(co jest również dobre w przypadku zlokalizowanych wyników i drukowania względnych czasów, takich jak „wczoraj”, „następna niedziela”, „4 dni temu” itp.):
String s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.NARROW);
System.out.println(s); // output: 2m 3s 456ms
s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.WIDE);
System.out.println(s); // output: 2 minutes, 3 seconds, and 456 milliseconds
s = PrettyTime.of(Locale.UK).print(dur, TextWidth.WIDE);
System.out.println(s); // output: 2 minutes, 3 seconds and 456 milliseconds
Szerokość tekstu określa, czy używane są skróty, czy nie. Format listy można również kontrolować, wybierając odpowiednie ustawienie regionalne. Na przykład standardowy angielski używa przecinka Oxform, podczas gdy w Wielkiej Brytanii nie. Najnowsza wersja v5.5 Time4J obsługuje ponad 90 języków i wykorzystuje tłumaczenia oparte na repozytorium CLDR (standard branżowy).
ten PrettyTime jest o wiele lepszy niż ten w drugiej odpowiedzi! szkoda, że nie znalazłem tego jako pierwszy.
ycomp
Nie wiem, dlaczego teraz są dwa głosy przeciw temu dobrze działającemu rozwiązaniu, więc zdecydowałem się rozszerzyć odpowiedź, podając więcej przykładów dotyczących analizowania (przeciwieństwo formatowania) i podkreślając niewłaściwe oczekiwanie PO.
Duration
zdefiniowany w rozsądnym standardzie ISO 8601 :PnYnMnDTnHnMnS
gdzieP
oznacza „Okres” i oznacza początek,T
oddziela część daty od części czasu, a pomiędzy nimi są opcjonalne wystąpienia liczby z pojedynczym -skrót liter. Na przykładPT4H30M
= cztery i pół godziny.%
i/
podzielić numer na części. Niemal łatwiejsze niż niektóre z proponowanych odpowiedzi./
i%
.Odpowiedzi:
Joda Time ma całkiem niezły sposób na zrobienie tego za pomocą PeriodFormatterBuilder .
Szybkie zwycięstwo:
PeriodFormat.getDefault().print(duration.toPeriod());
na przykład
//import org.joda.time.format.PeriodFormatter; //import org.joda.time.format.PeriodFormatterBuilder; //import org.joda.time.Duration; Duration duration = new Duration(123456); // in milliseconds PeriodFormatter formatter = new PeriodFormatterBuilder() .appendDays() .appendSuffix("d") .appendHours() .appendSuffix("h") .appendMinutes() .appendSuffix("m") .appendSeconds() .appendSuffix("s") .toFormatter(); String formatted = formatter.print(duration.toPeriod()); System.out.println(formatted);
źródło
PeriodType.daysTime()
lub.standard()
nie pomogłoZbudowałem proste rozwiązanie, używając Java 8
Duration.toString()
i trochę wyrażenia regularnego:public static String humanReadableFormat(Duration duration) { return duration.toString() .substring(2) .replaceAll("(\\d[HMS])(?!$)", "$1 ") .toLowerCase(); }
Wynik będzie wyglądał następująco:
- 5h - 7h 15m - 6h 50m 15s - 2h 5s - 0.1s
Jeśli nie chcesz między nimi spacji, po prostu usuń
replaceAll
.źródło
Duration::toString
są sformatowane zgodnie z dobrze zdefiniowaną i znaną normą ISO 8601 ..replaceAll("\\.\\d+", "")
przed wywołaniemtoLowerCase()
.Apache commons-lang zapewnia użyteczną klasę do wykonania tego zadania DurationFormatUtils
np.
DurationFormatUtils.formatDurationHMS( 15362 * 1000 ) )
=> 4: 16: 02.000 (H: m: s.millis)DurationFormatUtils.formatDurationISO( 15362 * 1000 ) )
=> P0Y0M0DT4H16M2.000S, por. ISO8601źródło
JodaTime ma
Period
klasę, która może reprezentować takie wielkości i może być renderowana (przezIsoPeriodFormat
) w formacie ISO8601PT4D1H3M5S
, np.Period period = new Period(millis); String formatted = ISOPeriodFormat.standard().print(period);
Jeśli ten format nie jest tym, którego potrzebujesz,
PeriodFormatterBuilder
umożliwia tworzenie dowolnych układów, w tym stylu C #4d1h3m5s
.źródło
new Period(millis).toString()
używaISOPeriodFormat.standard()
.W Javie 8 można również użyć
toString()
metodyjava.time.Duration
formatowania bez bibliotek zewnętrznych, używając reprezentacji sekundowej ISO 8601, takiej jak PT8H6M12.345S.źródło
Oto, jak możesz to zrobić, używając czystego kodu JDK:
import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; long diffTime = 215081000L; Duration duration = DatatypeFactory.newInstance().newDuration(diffTime); System.out.printf("%02d:%02d:%02d", duration.getDays() * 24 + duration.getHours(), duration.getMinutes(), duration.getSeconds());
źródło
org.threeten.extra.AmountFormats.wordBased
Projekt ThreeTen-Extra , który jest prowadzony przez Stephena Colebourne'a, autora JSR 310, java.time i Joda-Time , ma
AmountFormats
klasę, która współpracuje ze standardowymi klasami daty i czasu Java 8. Jest jednak dość rozwlekły, bez opcji na bardziej kompaktowe wyjście.Duration d = Duration.ofMinutes(1).plusSeconds(9).plusMillis(86); System.out.println(AmountFormats.wordBased(d, Locale.getDefault()));
1 minute, 9 seconds and 86 milliseconds
źródło
Java 9+
Duration d1 = Duration.ofDays(0); d1 = d1.plusHours(47); d1 = d1.plusMinutes(124); d1 = d1.plusSeconds(124); System.out.println(String.format("%s d %sh %sm %ss", d1.toDaysPart(), d1.toHoursPart(), d1.toMinutesPart(), d1.toSecondsPart()));
2 d 1h 6m 4s
źródło
Alternatywą dla podejścia konstruktora w Joda-Time byłoby rozwiązanie oparte na wzorcach . To jest oferowane przez moją bibliotekę Time4J . Przykład użycia klasy Duration.Formatter (dodano kilka spacji dla większej czytelności - usunięcie spacji da pożądany styl C #):
IsoUnit unit = ClockUnit.MILLIS; Duration<IsoUnit> dur = // normalized duration with multiple components Duration.of(123456, unit).with(Duration.STD_PERIOD); Duration.Formatter<IsoUnit> f = // create formatter/parser with optional millis Duration.Formatter.ofPattern("D'd' h'h' m'm' s[.fff]'s'"); System.out.println(f.format(dur)); // output: 0d 0h 2m 3.456s
Ten program formatujący może również drukować czasy trwania
java.time
-API (jednak funkcje normalizacji tego typu są mniej wydajne):System.out.println(f.format(java.time.Duration.ofMillis(123456))); // output: 0d 0h 2m 3.456s
Oczekiwanie OP, że „123456 ms jako długość zostanie wydrukowane jako 4d1h3m5s” jest obliczane w oczywiście nieprawidłowy sposób. Za powód przyjmuję niechlujstwo. Ten sam program formatujący czas trwania zdefiniowany powyżej może być również używany jako parser. Poniższy kod pokazuje, że „4d1h3m5s” odpowiada raczej
349385000 = 1000 * (4 * 86400 + 1 * 3600 + 3 * 60 + 5)
:System.out.println( f.parse("4d 1h 3m 5s") .toClockPeriodWithDaysAs24Hours() .with(unit.only()) .getPartialAmount(unit)); // 349385000
Innym sposobem jest użycie klasy
net.time4j.PrettyTime
(co jest również dobre w przypadku zlokalizowanych wyników i drukowania względnych czasów, takich jak „wczoraj”, „następna niedziela”, „4 dni temu” itp.):String s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.NARROW); System.out.println(s); // output: 2m 3s 456ms s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.WIDE); System.out.println(s); // output: 2 minutes, 3 seconds, and 456 milliseconds s = PrettyTime.of(Locale.UK).print(dur, TextWidth.WIDE); System.out.println(s); // output: 2 minutes, 3 seconds and 456 milliseconds
Szerokość tekstu określa, czy używane są skróty, czy nie. Format listy można również kontrolować, wybierając odpowiednie ustawienie regionalne. Na przykład standardowy angielski używa przecinka Oxform, podczas gdy w Wielkiej Brytanii nie. Najnowsza wersja v5.5 Time4J obsługuje ponad 90 języków i wykorzystuje tłumaczenia oparte na repozytorium CLDR (standard branżowy).
źródło
Wersja Java 8 oparta na odpowiedzi użytkownika678573 :
private static String humanReadableFormat(Duration duration) { return String.format("%s days and %sh %sm %ss", duration.toDays(), duration.toHours() - TimeUnit.DAYS.toHours(duration.toDays()), duration.toMinutes() - TimeUnit.HOURS.toMinutes(duration.toHours()), duration.getSeconds() - TimeUnit.MINUTES.toSeconds(duration.toMinutes())); }
... ponieważ w Javie 8 nie ma PeriodFormatter ani metod takich jak getHours, getMinutes, ...
Byłbym szczęśliwy, mogąc zobaczyć lepszą wersję dla Java 8.
źródło
Zdaję sobie sprawę, że może to nie pasować dokładnie do twojego przypadku użycia, ale PrettyTime może być tutaj przydatne.
PrettyTime p = new PrettyTime(); System.out.println(p.format(new Date())); //prints: “right now” System.out.println(p.format(new Date(1000*60*10))); //prints: “10 minutes from now”
źródło