361 Stimmen

Wie kann ich in Java die verstrichene Zeit messen?

Ich möchte so etwas haben:

public class Stream
{
    public startTime;
    public endTime;

    public getDuration()
    {
        return startTime - endTime;
    }
}

Außerdem ist es wichtig, dass z.B. bei einer Startzeit von 23:00 und einer Endzeit von 1:00 eine Dauer von 2:00 erreicht wird.

Welche Typen sind zu verwenden, um dies in Java zu erreichen?

713voto

Kevin Bourrillion Punkte 39545

Leider ist keine der zehn Antworten, die bisher gegeben wurden, ganz richtig.

Wenn Sie die verstrichene Zeit messen, und Sie möchten, dass sie richtig müssen Sie System.nanoTime() . Sie können nicht verwenden System.currentTimeMillis() Es sei denn, es stört Sie nicht, dass Ihr Ergebnis falsch ist.

Der Zweck der nanoTime ist zu messen verstrichen Zeit, und der Zweck der currentTimeMillis ist zu messen Wanduhr Zeit. Sie können das eine nicht für das andere verwenden. Der Grund dafür ist, dass die Uhr eines Computers nicht perfekt ist; sie weicht immer ab und muss gelegentlich korrigiert werden. Diese Korrektur kann entweder manuell erfolgen, oder es gibt bei den meisten Computern einen Prozess, der läuft und ständig kleine Korrekturen an der Systemuhr ("Wanduhr") vornimmt. Diese Korrekturen kommen in der Regel häufig vor. Eine weitere solche Korrektur erfolgt immer dann, wenn es eine Schaltsekunde gibt.

Seit nanoTime Da der Zweck der Messung der verstrichenen Zeit darin besteht, die Zeit zu messen, wird sie durch diese kleinen Korrekturen nicht beeinträchtigt. Sie ist das, was Sie verwenden wollen. Alle derzeit laufenden Zeitmessungen mit currentTimeMillis wird falsch sein - möglicherweise sogar negativ.

Sie werden vielleicht sagen: "Das hört sich nicht so an, als ob das jemals eine Rolle spielen würde", worauf ich antworte: "Vielleicht nicht, aber ist korrekter Code nicht einfach besser als falscher Code? Außerdem, nanoTime ist ohnehin kürzer zu tippen.

Zuvor veröffentlichte Haftungsausschlüsse über nanoTime die in der Regel nur eine Genauigkeit im Mikrosekundenbereich haben, sind gültig. Außerdem kann der Aufruf je nach den Umständen mehr als eine ganze Mikrosekunde dauern (wie auch der andere Aufruf), so dass man nicht erwarten kann, dass sehr kleine Intervalle korrekt gemessen werden.

238voto

Pascal Thivent Punkte 548176

Welche Typen sind zu verwenden, um dies in Java zu erreichen?

Die kurze Antwort lautet long . Nun mehr dazu, wie man misst...

System.currentTimeMillis()

Der "traditionelle" Weg, dies zu tun, ist in der Tat die Verwendung von [System.currentTimeMillis()](http://java.sun.com/javase/6/docs/api/java/lang/System.html#currentTimeMillis()) :

long startTime = System.currentTimeMillis();
// ... do something ...
long estimatedTime = System.currentTimeMillis() - startTime;

o.a.c.l.t.StopWatch

Beachten Sie, dass Commons Lang eine StopWatch Klasse, die zur Messung der Ausführungszeit in Millisekunden verwendet werden kann. Sie hat Methoden wie [split()](http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/time/StopWatch.html#split()) , [suspend()](http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/time/StopWatch.html#suspend()) , [resume()](http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/time/StopWatch.html#resume()) usw., die es ermöglichen, an verschiedenen Punkten der Ausführung Maßnahmen zu ergreifen, die Sie für zweckmäßig halten. Schauen Sie es sich an.

System.nanoTime()

Vielleicht bevorzugen Sie die Verwendung von System.nanoTime() wenn Sie extrem genaue Messungen der verstrichenen Zeit wünschen. Aus seiner Javadoc:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

Jamon

Eine andere Möglichkeit wäre die Verwendung von JAMon ein Werkzeug, das die Statistik (Ausführungszeit, Anzahl der Treffer, durchschnittliche Ausführungszeit, Minimum, Maximum, usw.) für jeden Code, der zwischen den Methoden start() und stop() liegt. Nachfolgend ein sehr einfaches Beispiel:

import com.jamonapi.*;
...
Monitor mon=MonitorFactory.start("myFirstMonitor");
...Code Being Timed...
mon.stop();

Auschecken dieser Artikel auf www.javaperformancetunning.com für eine gute Einführung.

AOP verwenden

Und schließlich, wenn Sie Ihren Code nicht mit diesen Messungen überladen wollen (oder wenn Sie den bestehenden Code nicht ändern können), dann wäre AOP eine perfekte Waffe. Ich werde dies nicht sehr ausführlich diskutieren, aber ich wollte es zumindest erwähnen.

Nachfolgend ein sehr einfacher Aspekt mit AspectJ und JAMon (hier wird der Kurzname des Pointcuts für den JAMon-Monitor verwendet, daher der Aufruf von thisJoinPoint.toShortString() ):

public aspect MonitorAspect {
    pointcut monitor() : execution(* *.ClassToMonitor.methodToMonitor(..));

    Object arround() : monitor() {
        Monitor monitor = MonitorFactory.start(thisJoinPoint.toShortString());
        Object returnedObject = proceed();
        monitor.stop();
        return returnedObject;
    }
}

Die Pointcut-Definition kann leicht angepasst werden, um jede Methode auf der Grundlage des Klassennamens, des Paketnamens, des Methodennamens oder einer beliebigen Kombination davon zu überwachen. Die Messung ist wirklich ein perfekter Anwendungsfall für AOP.

42voto

GHad Punkte 9561

Ihre neue Klasse:

public class TimeWatch {    
    long starts;

    public static TimeWatch start() {
        return new TimeWatch();
    }

    private TimeWatch() {
        reset();
    }

    public TimeWatch reset() {
        starts = System.currentTimeMillis();
        return this;
    }

    public long time() {
        long ends = System.currentTimeMillis();
        return ends - starts;
    }

    public long time(TimeUnit unit) {
        return unit.convert(time(), TimeUnit.MILLISECONDS);
    }
}

Verwendung:

    TimeWatch watch = TimeWatch.start();
    // do something
    long passedTimeInMs = watch.time();
    long passedTimeInSeconds = watch.time(TimeUnit.SECONDS);

Anschließend kann die vergangene Zeit in ein beliebiges Format umgewandelt werden, z. B. in einen Kalender

Grüß Gott, GHad

24voto

Basil Bourque Punkte 256611

Tl;dr

zum Beispiel, wenn die Startzeit 23:00 und die Endzeit 1:00 ist, um eine Dauer von 2:00 zu erhalten.

Nicht möglich. Wenn Sie nur die Tageszeit haben, bleibt die Uhr um Mitternacht stehen. Wie können wir ohne den Kontext der Daten wissen, ob Sie 1 Uhr am nächsten Tag, in der nächsten Woche oder im nächsten Jahrzehnt meinen?

Von 23.00 Uhr auf 1.00 Uhr zu wechseln bedeutet also rückwärts in der Zeit 22 Stunden, wobei die Zeiger der Uhr gegen den Uhrzeigersinn laufen. Siehe das Ergebnis unten, ein negativ zweiundzwanzig Stunden.

Duration.between(              // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    LocalTime.of( 23 , 0 ) ,   // A time-of-day without a date and without a time zone. 
    LocalTime.of( 1 , 0 )      // A time-of-day clock stops at midnight. So getting to 1 AM from 11 PM means going backwards 22 hours.
)                              // Return a `Duration` object.
.toString()                    // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT-22H

Die Überschreitung von Mitternacht erfordert neben der Tageszeit auch den größeren Kontext des Datums (siehe unten).

Wie kann ich in Java die verstrichene Zeit messen?

  1. Erfassen Sie den aktuellen Moment in UTC, mit [Instant.now()](https://docs.oracle.com/javase/10/docs/api/java/time/Instant.html#now()) .
  2. Halten Sie später einen weiteren solchen Moment fest.
  3. Übergeben Sie beides an Duration.between .
  4. (a) Aus dem Ergebnis Duration Objekts eine Anzahl von 24-Stunden-Tagen, Stunden, Minuten, Sekunden und Sekundenbruchteilen in Nanosekunden, indem Sie die verschiedenen to…Part Methoden.
    (b) Oder, rufen Sie an toString zur Erzeugung einer String in Standardformat ISO 8601 de PnYnMnDTnHnMnS .

Beispielcode, der ein Paar von Instant Objekte.

Duration.between(    // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    then ,           // Some other `Instant` object, captured earlier with `Instant.now()`.
    Instant.now()    // Capture the current moment in UTC with a resolution as fine as nanoseconds, depending on the limits of your host computer hardware clock and operating system. Generally you will get current moment in microseconds (six decimal digits of fractional second) in Java 9, 10, and 11, but only milliseconds in Java 8. 
)                    // Return a `Duration` object.
.toString()          // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT3M27.602197S

Neue Technologie in Java 8+

Dafür gibt es jetzt eine neue Technologie, die in Java 8 und höher integriert ist, die java.time Rahmen.

java.time

Das java.time-Framework ist definiert durch JSR 310 , inspiriert von dem sehr erfolgreichen Joda-Time Projekt, erweitert um das DreiZehn-Extra Projekt, und beschrieben in der Oracle-Tutorial .

Die alten Datums-Zeit-Klassen wie java.util.Date/.Calendar, die mit den ersten Java-Versionen mitgeliefert wurden, haben sich als schlecht entworfen, verwirrend und problematisch erwiesen. Sie wurden durch die java.time-Klassen abgelöst.

Auflösung

Andere Antworten behandeln die Auflösung.

Die java.time-Klassen haben Nanosekunde Auflösung, bis zu neun Ziffern eines Dezimalbruchteils einer Sekunde. Zum Beispiel, 2016-03-12T04:29:39.123456789Z .

Sowohl die alten java.util.Date/.Calendar-Klassen als auch die Joda-Time-Klassen haben eine Millisekunden-Auflösung (3 Ziffern des Bruches). Zum Beispiel, 2016-03-12T04:29:39.123Z .

In Java 8 wird der aktuelle Zeitpunkt aufgrund eines Legacy-Problems nur mit einer Auflösung von bis zu einer Millisekunde abgerufen. In Java 9 und höher kann die aktuelle Zeit bis zu einer Nanosekunden-Auflösung ermittelt werden, sofern die Hardware-Uhr Ihres Computers so fein läuft.

Tageszeit

Wenn Sie wirklich nur mit der Uhrzeit arbeiten wollen, ohne ein Datum oder eine Zeitzone, verwenden Sie die LocalTime Klasse.

LocalTime sooner = LocalTime.of ( 17, 00 );
LocalTime later = LocalTime.of ( 19, 00 );

A Duration stellt eine Zeitspanne in Form einer Anzahl von Sekunden plus Nanosekunden dar.

Duration duration = Duration.between ( sooner, later );

Dump auf die Konsole.

System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );

früher: 17:00 | später: 19:00 | Dauer: PT2H

ISO 8601

Beachten Sie die Standardausgabe von Duration::toString ist im Standard ISO 8601 Format. In diesem Format werden die P markiert den Anfang (wie in 'Punkt'), und das T trennt den Teil Jahre-Monate-Tage vom Teil Stunden-Minuten-Sekunden.

Mitternachtsüberquerung

Leider wird die Arbeit mit der Uhrzeit erst dann kompliziert, wenn man die Uhr über Mitternacht hinaus umdreht. Die LocalTime Klasse geht davon aus, dass Sie zu einem früheren Zeitpunkt des Tages zurückgehen wollen.

Mit dem gleichen Code wie oben, aber von 23:00 a 01:00 ergibt einen negativen Wert von zweiundzwanzig Stunden ( PT-22H ).

LocalTime sooner = LocalTime.of ( 23, 0 );
LocalTime later = LocalTime.of ( 1, 0 );

früher: 23:00 | später: 01:00 | Dauer: PT-22H

Datum-Uhrzeit

Wenn Sie beabsichtigen, Mitternacht zu überschreiten, ist es wahrscheinlich sinnvoller, mit Datums- und Uhrzeitwerten zu arbeiten als mit reinen Tageszeitwerten.

Zeitzone

Die Zeitzone ist für das Datum entscheidend. Wir geben also drei Punkte an: (1) das gewünschte Datum, (2) die gewünschte Uhrzeit und (3) die Zeitzone als Kontext, in dem wir das Datum und die Uhrzeit interpretieren. Hier wählen wir willkürlich die Zeitzone des Montréal Bereich.

Wenn Sie das Datum nur durch eine Abweichung von der UTC verwenden Sie eine ZoneOffset mit einer OffsetDateTime . Wenn Sie eine vollständige Zeitzone haben (Offset plus Regeln für die Behandlung von Anomalien wie Sommerzeit), verwenden Sie eine ZoneId mit einer ZonedDateTime .

LocalDate localDate = LocalDate.of ( 2016, 1, 23 );
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime sooner = ZonedDateTime.of ( localDate, LocalTime.of ( 23, 0 ), zoneId );

Als späteren Zeitpunkt geben wir den nächsten Tag um 1:00 Uhr an.

ZonedDateTime later = ZonedDateTime.of ( localDate.plusDays ( 1 ), LocalTime.of ( 1, 0 ), zoneId );

Wir berechnen die Duration auf die gleiche Weise wie oben beschrieben. Jetzt erhalten wir die zwei Stunden, die in dieser Frage erwartet werden.

Duration duration = Duration.between ( sooner, later );

Dump auf die Konsole.

System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );

früher: 2016-01-23T23:00-05:00[Amerika/Montreal] | später: 2016-01-24T01:00-05:00[Amerika/Montreal] | Dauer: PT2H

Sommerzeit

Wenn es sich bei den vorliegenden Datumszeiten um Sommerzeit oder eine andere derartige Anomalie handelte, würden sich die java.time-Klassen nach Bedarf anpassen. Lesen Sie das Klassendokument für Details.


Über java.time

Die java.time Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Erbe Datum-Zeit-Klassen wie java.util.Date , Calendar , & SimpleDateFormat .

Die Joda-Time Projekt, jetzt in Wartungsmodus rät zur Migration auf den java.time Klassen.

Weitere Informationen finden Sie in der Oracle-Tutorial . Und suchen Sie auf Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR 310 .

Sie können umtauschen java.time Objekte direkt mit Ihrer Datenbank. Verwenden Sie eine JDBC-Treiber übereinstimmend mit JDBC 4.2 oder später. Keine Notwendigkeit für Strings, keine Notwendigkeit für java.sql.* Klassen.

Wo erhält man die java.time-Klassen?

  • Java SE 8 , Java SE 9 , Java SE 10 und später
    • Eingebaut.
    • Teil der Standard-Java-API mit einer gebündelten Implementierung.
    • Java 9 fügt einige kleinere Funktionen und Korrekturen hinzu.
  • Java SE 6 y Java SE 7
    • Ein Großteil der java.time-Funktionalität wurde in Java 6 und 7 zurückportiert in DreiZehn-Backport .
  • Android
    • Spätere Versionen von Android bündeln Implementierungen der java.time-Klassen.
    • Bei älteren Android-Betriebssystemen (<26) ist die DreiZehnABP Projekt passt sich an DreiZehn-Backport (siehe oben). Siehe Wie benutzt man ThreeTenABP .

Die DreiZehn-Extra Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt dient als Versuchsfeld für mögliche zukünftige Erweiterungen von java.time. Sie finden hier vielleicht einige nützliche Klassen wie Interval , YearWeek , YearQuarter und mehr .

23voto

David Bliss Punkte 361

Wenn der Zweck einfach darin besteht, grobe Zeitinformationen in Ihre Programmprotokolle zu drucken, dann besteht die einfache Lösung für Java-Projekte darin, keine eigenen Stoppuhr- oder Timer-Klassen zu schreiben, sondern einfach die [org.apache.commons.lang.time.StopWatch](https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/StopWatch.html#toSplitString()) Klasse, die Teil von Apache Commons Lang ist.

final StopWatch stopwatch = new StopWatch();
stopwatch.start();
LOGGER.debug("Starting long calculations: {}", stopwatch);
...
LOGGER.debug("Time after key part of calcuation: {}", stopwatch);
...
LOGGER.debug("Finished calculating {}", stopwatch);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X