Zu Ihrer Information, das Format, das Sie zu beschreiben scheinen, ist Durationin der vernünftigen Norm ISO 8601 definiert : PnYnMnDTnHnMnSDabei Pbedeutet "Punkt" und markiert den Anfang, Ttrennt den Datums- und den Zeitabschnitt und dazwischen sind optionale Vorkommen einer Zahl mit einer einzigen -Briefkürzel. Zum Beispiel PT4H30M= viereinhalb Stunden.
Basil Bourque
1
Wenn alles andere fehlschlägt, ist es sehr einfach, es selbst zu tun. Verwenden Sie einfach aufeinanderfolgende Anwendungen von %und /, um die Anzahl in Teile aufzuteilen. Fast einfacher als einige der vorgeschlagenen Antworten.
Hot Licks
@HotLicks Überlassen Sie es den Bibliotheksmethoden für viel saubereren und klareren Code als die Verwendung von /und %.
Ole VV
Ja, in den letzten 8 Jahren, seit ich diese Frage gestellt habe (!), Bin ich zu joda time übergegangen, was sehr gut zu meinem Anwendungsfall passt
phatmanace
@phatmanace Das Joda-Time- Projekt befindet sich jetzt im Wartungsmodus und empfiehlt die Migration zu den in Java 8 und höher integrierten java.time- Klassen.
Aus einer Antwort unten geht hervor, dass eine Instanz von Period direkt erstellt werden kann, ohne zuerst eine Duration-Instanz zu erstellen und diese dann in Period zu konvertieren. ZB Periodenperiode = neue Periode (Millis); String formatiert = formatter.print (Punkt);
Basil Vandegriend
7
Achten Sie auf diese Konvertierung von "duration.toPeriod ()". Wenn die Dauer ziemlich groß ist, bleibt der Tagesanteil ab 0. Der Stundenanteil wächst weiter. Sie erhalten 25h10m23s, aber niemals das "d". Der Grund dafür ist, dass es keinen völlig korrekten Weg gibt, Stunden in Tage auf Jodas strenge Weise umzurechnen. In den meisten Fällen können Sie, wenn Sie zwei Zeitpunkte vergleichen und drucken möchten, anstelle der neuen Dauer (t1, t2) .toPeriod () eine neue Periode (t1, t2) ausführen.
Boon
@Boon wissen Sie, wie man die Dauer in Bezug auf Tage in einen Zeitraum umwandelt? Ich verwende die Dauer, ab der ich die Sekunde in meinem Timer ersetzen kann. Ereigniseinstellung PeriodType.daysTime()oder .standard()hat nicht geholfen
murt
4
@murt Wenn Sie wirklich möchten und die Standarddefinition eines Tages akzeptieren können, können Sie im obigen Code "formatter.print (duration.toPeriod (). normalizedStandard ())" verwenden. Habe Spaß!
Boon
74
Ich habe eine einfache Lösung mit Java 8 Duration.toString()und ein bisschen Regex erstellt:
Sie sollten sich niemals auf die Ausgabe von toStrong () verlassen, da sich dies in weiteren Versionen ändern kann.
Weltraumschaf
12
@Weltraumschaf es ist unwahrscheinlich, dass es sich ändert, da es im javadoc angegeben ist
aditsu beenden, weil SE
9
@Weltraumschaf Es ist unwahrscheinlich, dass sich die Ausgabe von Duration::toStringgemäß der genau definierten und abgenutzten Norm ISO 8601 formatiert .
Basil Bourque
Wenn Sie keine Brüche möchten, fügen Sie diese .replaceAll("\\.\\d+", "")vor dem Aufruf hinzu toLowerCase().
zb226
1
@Weltraumschaf Dein Punkt ist im Allgemeinen richtig und ich würde mich nicht auf die toString () Ausgabe der meisten Klassen verlassen. Aber in diesem speziellen Fall der Methode Definition besagt , dass seine Ausgabe folgt den ISO-8601 - Standard, wie Sie in der Methode sehen können Javadoc . Es ist also kein Implementierungsdetail wie in den meisten Klassen, daher würde ich nicht erwarten, dass sich eine so ausgereifte Sprache wie Java so ändert,
lucasls
13
Apache commons-lang bietet eine nützliche Klasse, um dies ebenfalls zu erledigen. DurationFormatUtils
Period period =newPeriod(millis);String formatted =ISOPeriodFormat.standard().print(period);
Wenn dieses Format nicht das gewünschte ist, PeriodFormatterBuilderkönnen Sie beliebige Layouts zusammenstellen, einschließlich Ihres C # -Stils 4d1h3m5s.
Das ThreeTen-Extra- Projekt, das von Stephen Colebourne, dem Autor von JSR 310, java.time und Joda-Time , verwaltet wird, verfügt über eine AmountFormatsKlasse, die mit den Standard-Java 8-Datumszeitklassen funktioniert. Es ist jedoch ziemlich ausführlich und bietet keine Option für eine kompaktere Ausgabe.
Duration d =Duration.ofMinutes(1).plusSeconds(9).plusMillis(86);System.out.println(AmountFormats.wordBased(d,Locale.getDefault()));
Wow, schön zu wissen, ich habe diese Funktion nicht gesehen. Hat jedoch einen großen Fehler: Das Oxford-Komma fehlt .
Basil Bourque
4
@BasilBourque Das Oxford-Komma ist typisch für die USA, aber interessanterweise nicht für Großbritannien. Meine lib Time4J (die eine weitaus bessere Internationalisierung aufweist) unterstützt diese Unterscheidung in der Klasse net.time4j.PrettyTime und ermöglicht auf Wunsch auch die Steuerung der kompakten Ausgabe.
Eine Alternative zum Builder-Ansatz von Joda-Time wäre eine musterbasierte Lösung . Dies wird von meiner Bibliothek Time4J angeboten . Beispiel mit der Klasse Duration.Formatter (einige Leerzeichen zur besseren Lesbarkeit hinzugefügt - das Entfernen der Leerzeichen ergibt den gewünschten C # -Stil):
IsoUnit unit =ClockUnit.MILLIS;Duration<IsoUnit> dur =// normalized duration with multiple componentsDuration.of(123456, unit).with(Duration.STD_PERIOD);Duration.Formatter<IsoUnit> f =// create formatter/parser with optional millisDuration.Formatter.ofPattern("D'd' h'h' m'm' s[.fff]'s'");System.out.println(f.format(dur));// output: 0d 0h 2m 3.456s
Dieser Formatierer kann auch die Dauer von java.time-API drucken (die Normalisierungsfunktionen dieses Typs sind jedoch weniger leistungsfähig):
Die Erwartung des OP, dass "123456 ms so lang wie 4d1h3m5s gedruckt werden", wird offensichtlich falsch berechnet. Ich nehme Schlamperei als Grund an. Der oben definierte Dauerformatierer kann auch als Parser verwendet werden. Der folgende Code zeigt, dass "4d1h3m5s" eher entspricht 349385000 = 1000 * (4 * 86400 + 1 * 3600 + 3 * 60 + 5):
Eine andere Möglichkeit ist die Verwendung der Klasse net.time4j.PrettyTime(die auch für die lokalisierte Ausgabe und das Drucken relativer Zeiten wie "gestern", "nächsten Sonntag", "vor 4 Tagen" usw. geeignet ist):
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
Die Textbreite steuert, ob Abkürzungen verwendet werden oder nicht. Das Listenformat kann auch durch Auswahl des entsprechenden Gebietsschemas gesteuert werden. In Standard-Englisch wird beispielsweise das Oxform-Komma verwendet, in Großbritannien jedoch nicht. Die neueste Version 5.5 von Time4J unterstützt mehr als 90 Sprachen und verwendet Übersetzungen, die auf dem CLDR-Repository (einem Industriestandard) basieren.
Diese PrettyTime ist viel besser als die in der anderen Antwort! Schade, dass ich das nicht zuerst gefunden habe.
ycomp
Ich weiß nicht, warum es jetzt zwei Abstimmungen für diese gut funktionierende Lösung gibt, deshalb habe ich beschlossen, die Antwort zu erweitern, indem ich weitere Beispiele auch zum Parsen (das Gegenteil von Formatierung) gebe und die falsche Erwartung des OP hervorhole.
@erickdeoliveiraleal Vielen Dank für den Hinweis. Ich glaube, ich habe ursprünglich den Code für groovy geschrieben, also könnte es in dieser Sprache funktioniert haben. Ich habe es jetzt für Java korrigiert.
Torsten
3
Mir ist klar, dass dies möglicherweise nicht genau zu Ihrem Anwendungsfall passt, aber PrettyTime kann hier hilfreich sein.
PrettyTime p =newPrettyTime();System.out.println(p.format(newDate()));//prints: “right now”System.out.println(p.format(newDate(1000*60*10)));//prints: “10 minutes from now”
Duration
in der vernünftigen Norm ISO 8601 definiert :PnYnMnDTnHnMnS
DabeiP
bedeutet "Punkt" und markiert den Anfang,T
trennt den Datums- und den Zeitabschnitt und dazwischen sind optionale Vorkommen einer Zahl mit einer einzigen -Briefkürzel. Zum BeispielPT4H30M
= viereinhalb Stunden.%
und/
, um die Anzahl in Teile aufzuteilen. Fast einfacher als einige der vorgeschlagenen Antworten./
und%
.Antworten:
Joda Time hat eine ziemlich gute Möglichkeit, dies mit einem PeriodFormatterBuilder zu tun .
Schneller Gewinn:
PeriodFormat.getDefault().print(duration.toPeriod());
z.B
quelle
PeriodType.daysTime()
oder.standard()
hat nicht geholfenIch habe eine einfache Lösung mit Java 8
Duration.toString()
und ein bisschen Regex erstellt:Das Ergebnis sieht folgendermaßen aus:
Wenn Sie keine Leerzeichen dazwischen möchten, entfernen Sie einfach
replaceAll
.quelle
Duration::toString
gemäß der genau definierten und abgenutzten Norm ISO 8601 formatiert ..replaceAll("\\.\\d+", "")
vor dem Aufruf hinzutoLowerCase()
.Apache commons-lang bietet eine nützliche Klasse, um dies ebenfalls zu erledigen. DurationFormatUtils
zB
DurationFormatUtils.formatDurationHMS( 15362 * 1000 ) )
=> 4: 16: 02.000 (H: m: s.millis)DurationFormatUtils.formatDurationISO( 15362 * 1000 ) )
=> P0Y0M0DT4H16M2.000S, vgl. ISO8601quelle
JodaTime hat eine
Period
Klasse, die solche Größen darstellen kann und (viaIsoPeriodFormat
) im ISO8601- Format gerendert werden kannPT4D1H3M5S
, zWenn dieses Format nicht das gewünschte ist,
PeriodFormatterBuilder
können Sie beliebige Layouts zusammenstellen, einschließlich Ihres C # -Stils4d1h3m5s
.quelle
new Period(millis).toString()
Verwendet nur als Hinweis dieISOPeriodFormat.standard()
Standardeinstellung.Mit Java 8 können Sie auch die
toString()
Methode verwenden,java.time.Duration
um es ohne externe Bibliotheken mit einer auf ISO 8601 Sekunden basierenden Darstellung wie PT8H6M12.345S zu formatieren.quelle
So können Sie dies mit reinem JDK-Code tun:
quelle
org.threeten.extra.AmountFormats.wordBased
Das ThreeTen-Extra- Projekt, das von Stephen Colebourne, dem Autor von JSR 310, java.time und Joda-Time , verwaltet wird, verfügt über eine
AmountFormats
Klasse, die mit den Standard-Java 8-Datumszeitklassen funktioniert. Es ist jedoch ziemlich ausführlich und bietet keine Option für eine kompaktere Ausgabe.1 minute, 9 seconds and 86 milliseconds
quelle
Java 9+
2 d 1h 6m 4s
quelle
Eine Alternative zum Builder-Ansatz von Joda-Time wäre eine musterbasierte Lösung . Dies wird von meiner Bibliothek Time4J angeboten . Beispiel mit der Klasse Duration.Formatter (einige Leerzeichen zur besseren Lesbarkeit hinzugefügt - das Entfernen der Leerzeichen ergibt den gewünschten C # -Stil):
Dieser Formatierer kann auch die Dauer von
java.time
-API drucken (die Normalisierungsfunktionen dieses Typs sind jedoch weniger leistungsfähig):Die Erwartung des OP, dass "123456 ms so lang wie 4d1h3m5s gedruckt werden", wird offensichtlich falsch berechnet. Ich nehme Schlamperei als Grund an. Der oben definierte Dauerformatierer kann auch als Parser verwendet werden. Der folgende Code zeigt, dass "4d1h3m5s" eher entspricht
349385000 = 1000 * (4 * 86400 + 1 * 3600 + 3 * 60 + 5)
:Eine andere Möglichkeit ist die Verwendung der Klasse
net.time4j.PrettyTime
(die auch für die lokalisierte Ausgabe und das Drucken relativer Zeiten wie "gestern", "nächsten Sonntag", "vor 4 Tagen" usw. geeignet ist):Die Textbreite steuert, ob Abkürzungen verwendet werden oder nicht. Das Listenformat kann auch durch Auswahl des entsprechenden Gebietsschemas gesteuert werden. In Standard-Englisch wird beispielsweise das Oxform-Komma verwendet, in Großbritannien jedoch nicht. Die neueste Version 5.5 von Time4J unterstützt mehr als 90 Sprachen und verwendet Übersetzungen, die auf dem CLDR-Repository (einem Industriestandard) basieren.
quelle
Eine Java 8- Version basierend auf der Antwort von user678573 :
... da es in Java 8 keinen PeriodFormatter gibt und keine Methoden wie getHours, getMinutes, ...
Ich würde mich freuen, eine bessere Version für Java 8 zu sehen.
quelle
Mir ist klar, dass dies möglicherweise nicht genau zu Ihrem Anwendungsfall passt, aber PrettyTime kann hier hilfreich sein.
quelle