Ich mache eine Stoppuhr, bei der ich Java SimpleDateFormat verwende, um die Anzahl der Millisekunden in ein Nice-Format "hh: mm: ss: SSS" zu konvertieren. Das Problem ist, dass das Stundenfeld immer eine Zufallszahl enthält. Hier ist der Code, den ich verwende:
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");
String strDate = sdf.format(millis);
return strDate;
}
Wenn ich den hh-Teil abnehme, funktioniert es gut. Andernfalls wird im hh-Teil etwas zufällig wie "07" angezeigt, auch wenn das übergebene Argument (Anzahl Millisekunden) Null ist.
Ich weiß nicht viel über die SimpleDateFormat-Klasse. Danke für jede Hilfe.
So habe ich es gemacht, indem ich nur das Standard-JDK verwendet habe (dies wird bis zu Java 1.1 funktionieren, indem StringBuilder
zurück in StringBuffer
geändert wird):
static public String formatMillis(long val) {
StringBuilder buf=new StringBuilder(20);
String sgn="";
if(val<0) { sgn="-"; val=Math.abs(val); }
append(buf,sgn,0,(val/3600000)); val%=3600000;
append(buf,":",2,(val/ 60000)); val%= 60000;
append(buf,":",2,(val/ 1000)); val%= 1000;
append(buf,".",3,(val ));
return buf.toString();
}
/** Append a right-aligned and zero-padded numeric value to a `StringBuilder`. */
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
tgt.append(pfx);
if(dgt>1) {
int pad=(dgt-1);
for(long xa=val; xa>9 && pad>0; xa/=10) { pad--; }
for(int xa=0; xa<pad; xa++ ) { tgt.append('0'); }
}
tgt.append(val);
}
TimeUnit
integriert.Was Sie verwenden möchten, ist Java.util.concurrent.TimeUnit , um mit Intervallen zu arbeiten.
SimpleDateFormat
macht genau das, was es klingt, formatiert Instanzen von Java.util.Date
oder konvertiert in Ihrem Fall den long
-Wert in den Kontext eines Java.util.Date
und weiß nicht, was Sie mit Intervalle tun sollen anscheinend arbeiten mit.
Sie können dies ganz einfach tun, ohne auf externe Bibliotheken wie JodaTime zurückgreifen zu müssen.
import Java.util.concurrent.TimeUnit;
public class Main
{
private static String formatInterval(final long l)
{
final long hr = TimeUnit.MILLISECONDS.toHours(l);
final long min = TimeUnit.MILLISECONDS.toMinutes(l - TimeUnit.HOURS.toMillis(hr));
final long sec = TimeUnit.MILLISECONDS.toSeconds(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
final long ms = TimeUnit.MILLISECONDS.toMillis(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
}
public static void main(final String[] args)
{
System.out.println(formatInterval(Long.parseLong(args[0])));
}
}
Die Ausgabe wird in etwa wie folgt formatiert
13:00:00.000
Eine kürzere Möglichkeit, dies zu tun, ist die Verwendung von DurationFormatUtils class in Apache Commons Lang :
public static String formatTime(long millis) {
return DurationFormatUtils.formatDuration(millis, "HH:mm:ss.S");
}
Warum nicht das?
public static String GetFormattedInterval(final long ms) {
long millis = ms % 1000;
long x = ms / 1000;
long seconds = x % 60;
x /= 60;
long minutes = x % 60;
x /= 60;
long hours = x % 24;
return String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, millis);
}
Dies ist der erste Teil von Joda, den ich gemacht habe, wo es langweiliger schien als die Unterstützung durch JDK. Eine Joda-Implementierung für das angeforderte Format (mit einigen Annahmen über Nullfelder) ist:
public void printDuration(long milliSecs)
{
PeriodFormatter formatter = new PeriodFormatterBuilder()
.printZeroIfSupported()
.appendHours()
.appendSeparator(":")
.minimumPrintedDigits(2)
.appendMinutes()
.appendSeparator(":")
.appendSecondsWithMillis()
.toFormatter();
System.out.println(formatter.print(new Period(milliSecs)));
}
Bei der Überprüfung der anderen Antworten kam ich mit dieser Funktion ...
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 );
}
}
Hier ist was los ist. Wenn Sie Millisekunden übergeben, ist diese Zahl relativ zum 1. Januar 1970. Wenn Sie 0 übergeben, wird dieses Datum in die lokale Zeitzone umgewandelt. Wenn Sie sich in der Zentralzeit befinden, dann ist das 7 Uhr. Wenn Sie dies ausführen, ist alles sinnvoll.
new SimpleDateFormat().format(0) => 12/31/69 7:00 PM
Edit, ich glaube, Sie wollen abgelaufene Zeit bekommen. Dafür empfehle ich die Verwendung von JodaTime , was dies bereits ziemlich gut macht. Sie machen so etwas
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendHours()
.appendSuffix(" hour", " hours")
.appendSeparator(" and ")
.appendMinutes()
.appendSuffix(" minute", " minutes")
.appendSeparator(" and ")
.appendSeconds()
.appendSuffix(" second", " seconds")
.toFormatter();
String formattedText = formatter.print(new Period(elapsedMilliSeconds));
Das Format richtet sich nach Ihrer lokalen Zeitzone. Wenn Sie also 0 übergeben, wird 0 GMT angenommen und in Ihre lokale Zeitzone konvertiert.
Dieses funktioniert zwar, aber ich scheine die Absicht der Methode zu verändern :-).
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
String strDate = sdf.format(millis - 3600000);
return strDate;
}
Für diejenigen von Ihnen, die wirklich wissen, wie dies funktioniert, werden Sie wahrscheinlich einige Vorbehalte finden.
Hier ist eine andere Möglichkeit, dies zu tun. Vollständig in sich geschlossen und vollständig abwärtskompatibel. Unbegrenzte Anzahl von Tagen.
private static String slf(double n) {
return String.valueOf(Double.valueOf(Math.floor(n)).longValue());
}
public static String timeSpan(long timeInMs) {
double t = Double.valueOf(timeInMs);
if(t < 1000d)
return slf(t) + "ms";
if(t < 60000d)
return slf(t / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 3600000d)
return slf(t / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 86400000d)
return slf(t / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
return slf(t / 86400000d) + "d " +
slf((t % 86400000d) / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
}
Einfache Formatierung für weniger als 24 Stunden. Über 24 Stunden zeigt der Code nur die Stunden innerhalb des nächsten Tages an und addiert den verstrichenen Tag nicht zu den Stunden.
public static String formatElapsedTime(long milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
}
Fehlende Funktionen im Beispielcode:
public static String formatElapsedTimeOver24h(long milliseconds) {
// Compiler will take care of constant arithmetics
if (24 * 60 * 60 * 1000 > milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
} else {
SimpleDateFormat sdf = new SimpleDateFormat(":mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// Keep long data type
// Compiler will take care of constant arithmetics
long hours = milliseconds / (60L * 60L * 1000L);
return hours + sdf.format(milliseconds);
}
}
Verwenden Sie ein einfaches Java Calendar
für Intervalle bis zu einem Tag (24 Stunden). Siehe meine Antwort auf die Frage: Wie formatiere ich Zeitintervalle in Java?
LocalTime // Represents a time-of-day, without date and without time zone.
.ofNanoOfDay( // Convert a count of nanoseconds into a time-of-day in a generic 24-hour day, ignoring real-world anomalies such as Daylight Saving Time (DST).
Duration // Class that represents a span-of-time not attached to the timeline.
.of( milliseconds ) // Parse your count of milliseconds as a span-of-time.
.toNanos() // Extract total number of nanoseconds in this span-of-time.
) // Returns a `LocalDate` object.
.toString() // Generate text in standard ISO 8601 format for a time-of-day (*not* recommended by me).
Java.time.Duration
Die richtige Klasse für eine Zeitspanne, die nicht mit der Zeitachse verknüpft ist, ist Duration
. Verwenden Sie für eine Skala von Jahren, Monaten und Tagen Period
.
Duration d = Duration.of( milliseconds ) ;
Ich schlage vor, Sie vermeiden, eine Zeitspanne im Uhrzeitformat HH: MM: SS zu melden. Ich habe gesehen, dass die inhärente Mehrdeutigkeit zu Fehlinterpretationen und Verwirrung in echten Geschäftsanwendungen führt.
Es gibt einen Standard für die Meldung solcher Werte: definiert in ISO 8601 : PnYnMnDTnHnMnS
. Das P
markiert den Anfang, während das T
einen Teil von Jahr, Monat, Tag von einem Teil von Stunde, Minute und Sekunde trennt.
Die Java.time-Klassen verwenden beim Parsen/Generieren von Zeichenfolgen standardmäßig die ISO 8601-Standardformate. Dies schließt die Klasse Duration
ein.
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toString() ;
Siehe dies Code wird live auf IdeOne.com ausgeführt .
PT1H23M45.678S
Diese ISO 8601-Zeichenfolgen können sowohl analysiert als auch generiert werden.
Duration d = Duration.parse( "PT1H23M45.678S" ) ;
Wenn Sie jedoch darauf bestehen, das Uhrzeitformat für Ihre Dauer zu verwenden, können Sie einen solchen Stich zusammenstellen, indem Sie die Methoden to…Part
Für das Objekt Duration
aufrufen.
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toHoursPart() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() + "." + TimeUnit.NANOSECONDS.toMillis( d.toNanosPart() ) ;
1: 23: 45.678
Oder wir könnten die Klasse LocalTime
missbrauchen, um Ihre Zeichenfolge zu erstellen.
Duration d = Duration.ofMillis( 5_025_678L ) ;
long nanoOfDay = d.toNanos() ;
LocalTime localTimeBogus = LocalTime.ofNanoOfDay( nanoOfDay ) ;
String output = localTimeBogus.toString() ;
Auch hier können Sie dies sehen Code wird live auf IdeOne.com ausgeführt .
01: 23: 45.678