web-dev-qa-db-fra.com

Comment mesurer le temps écoulé en Java?

Je veux avoir quelque chose comme ça:

public class Stream
{
    public startTime;
    public endTime;

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

De plus, il est important que, par exemple, si l'heure de début commence à 23h00 et à 13h00 pour obtenir l'heure, elle doit durer 2h00.

Quels types utiliser pour accomplir cela en Java?

301
Omu

Malheureusement, aucune des dix réponses affichées jusqu’à présent n’est tout à fait juste.

Si vous mesurez le temps écoulé et que vous voulez qu'il soit correct , vous devez utiliser System.nanoTime(). Vous ne pouvez pas utiliser System.currentTimeMillis(), à moins que votre résultat ne soit pas faux.

Le but de nanoTime est de mesurer écoulé temps, et le but de currentTimeMillis est de mesurer horloge murale temps. Vous ne pouvez pas utiliser l'un à l'autre fin. La raison en est qu'aucune horloge d'ordinateur n'est parfaite; il dérive toujours et doit parfois être corrigé. Cette correction peut être effectuée manuellement ou dans le cas de la plupart des machines, un processus est en cours d'exécution et génère en permanence de petites corrections sur l'horloge système ("horloge murale"). Celles-ci ont tendance à se produire souvent. Une autre correction de ce type se produit chaque fois qu'il y a une seconde intercalaire.

Étant donné que nanoTime a pour but de mesurer le temps écoulé, aucune de ces corrections mineures n’affectera votre recherche. C'est ce que vous voulez utiliser. Tous les horaires en cours avec currentTimeMillis seront décalés, voire négatifs.

Vous pouvez dire, "cela ne semble pas que cela aurait vraiment une telle importance", ce à quoi je dis, peut-être que non, mais dans l'ensemble, un code correct n'est-il pas simplement meilleur qu'un code incorrect? De plus, nanoTime est plus court à taper de toute façon.

Les renonciations précédemment publiées concernant la nanoTime n'ayant généralement qu'une précision de l'ordre de la microseconde sont valables. En outre, l'invocation peut prendre plus d'une microseconde, selon les circonstances (comme dans l'autre cas). Ne vous attendez donc pas à chronométrer correctement de très très petits intervalles.

598
Kevin Bourrillion

Quels types utiliser pour accomplir cela en Java?

La réponse courte est une long. Maintenant, plus sur comment mesurer ...

System.currentTimeMillis ()

La méthode "traditionnelle" consiste à utiliser System.currentTimeMillis() :

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

o.a.c.l.t.StopWatch

Notez que Commons Lang a la classe StopWatch qui peut être utilisée pour mesurer le temps d’exécution en millisecondes. Il a des méthodes comme split() , suspend() , resume() , etc. qui permettent de prendre des mesures à différents moments de l'exécution et que vous pouvez trouver commodes. Jetez un coup d'oeil.

System.nanoTime ()

Vous préférerez peut-être utiliser System.nanoTime() si vous recherchez des mesures extrêmement précises du temps écoulé. De son javadoc: 

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

Jamon

Une autre option serait d’utiliser JAMon , un outil qui rassemble statistics (temps d’exécution, nombre de hits, temps moyen d’exécution, min, max, etc.) pour tout code compris entre start () et stop. () méthodes. Ci-dessous, un exemple très simple:

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

Découvrez cet article sur www.javaperformancetunning.com pour une bonne introduction.

Utiliser l'AOP

Enfin, si vous ne voulez pas encombrer votre code avec ces mesures (ou si vous ne pouvez pas modifier le code existant), alors AOP serait une arme parfaite. Je ne vais pas en discuter très profondément mais je voulais au moins en parler. 

Ci-dessous, un aspect très simple utilisant AspectJ et JAMon (ici, le nom abrégé du pointcut sera utilisé pour le moniteur JAMon, d'où l'appel à 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;
    }
}

La définition de pointcut pourrait être facilement adaptée pour surveiller toute méthode basée sur le nom de la classe, le nom du package, le nom de la méthode ou toute combinaison de ceux-ci. La mesure est vraiment un cas d'utilisation idéal pour AOP.

199
Pascal Thivent

Votre nouvelle classe:

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);
    }
}

Usage:

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

Ensuite, le temps écoulé peut être converti au format de votre choix, avec un calendrier par exemple.

Greetz, GHad

36
GHad

Si le but est simplement d’imprimer des informations de minutage approximatives dans les journaux de votre programme, la solution simple pour les projets Java n’est pas d’écrire vos propres classes de chronomètre ou de minuterie, mais d’utiliser la classe org.Apache.commons.lang.time.StopWatch d'Apache Commons Lang.

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);
19
David Bliss

Java fournit la méthode statique System.currentTimeMillis(). Et cela retourne une valeur longue, donc c'est une bonne référence. Beaucoup d'autres classes acceptent un paramètre 'timeInMillis' qui est également long.

Et beaucoup de gens trouvent plus facile d’utiliser la bibliothèque Joda Time pour faire des calculs de date et d’heure.

7
Andreas_D

Quels types utiliser pour y parvenir en Java?

Réponse: long

public class Stream {
    public long startTime;
    public long endTime;

    public long getDuration() {
        return endTime - startTime;
    }
    // I  would add
    public void start() {
        startTime = System.currentTimeMillis();
    }
    public void stop() {
         endTime = System.currentTimeMillis();
     }
}

Usage:

  Stream s = .... 

  s.start();

  // do something for a while 

  s.stop();

  s.getDuration(); // gives the elapsed time in milliseconds. 

C'est ma réponse directe à votre première question. 

Pour la dernière "note", je vous suggère d'utiliser Joda Time. Il contient une classe interval adaptée à vos besoins.

6
OscarRyz

Il est à noter que

  • System.currentTimeMillis () n'a au mieux qu'une précision de la milliseconde. Cela vaut au moins 16 ms sur certains systèmes Windows. Son coût inférieur à celui des solutions alternatives <200 ns.
  • System.nanoTime () n’est précis qu’en quelques secondes sur la plupart des systèmes et peut sauter sur les systèmes Windows par 100 microsecondes (c’est-à-dire qu’il n’est parfois pas aussi précis qu’il apparaît)
  • Le calendrier est un moyen très coûteux de calculer le temps. (Je peux penser en dehors de XMLGregorianCalendar) Parfois, c'est la solution la plus appropriée, mais sachez que vous ne devez utiliser que de longs intervalles.
6
Peter Lawrey

Si vous préférez utiliser l'API Calendar de Java , vous pouvez essayer ceci:

Date startingTime = Calendar.getInstance().getTime();
//later on
Date now = Calendar.getInstance().getTime();
long timeElapsed = now.getTime() - startingTime.getTime();
3
James McMahon

Si vous écrivez une application qui doit traiter des durées, jetez un coup d’œil à Joda-Time qui a une classe spécifique pour la gestion des durées, des intervalles et des périodes. Votre méthode getDuration() semble pouvoir renvoyer un intervalle Joda-Time:

DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);

public Interval getInterval() {
    Interval interval = new Interval(start, end);
}
3
David Bliss

Si vous obtenez votre horodatage de System.currentTimeMillis(), vos variables de temps devraient être longues.

1
uckelman
Byte Stream Reader Elapsed Time for 23.7 MB is 96 secs

import Java.io.*;
import Java.io.IOException;
import Java.util.Scanner;

class ElaspedTimetoCopyAFileUsingByteStream
{

    private long startTime = 0;
    private long stopTime = 0;
    private boolean running = false;


    public void start() 
    {
        this.startTime = System.currentTimeMillis();
        this.running = true;
    }


    public void stop() 
    {
        this.stopTime = System.currentTimeMillis();
        this.running = false;
    }



    public long getElapsedTime() 
    {
        long elapsed;
        if (running) {
             elapsed = (System.currentTimeMillis() - startTime);
        }
        else {
            elapsed = (stopTime - startTime);
        }
        return elapsed;
    }



    public long getElapsedTimeSecs()                 
    {
        long elapsed;
        if (running) 
        {
            elapsed = ((System.currentTimeMillis() - startTime) / 1000);
        }
        else
        {
            elapsed = ((stopTime - startTime) / 1000);
        }
        return elapsed;
    }





    public static void main(String[] args) throws IOException
    {
        ElaspedTimetoCopyAFileUsingByteStream  s = new ElaspedTimetoCopyAFileUsingByteStream();
        s.start();

        FileInputStream in = null;
        FileOutputStream out = null;

      try {
         in = new FileInputStream("vowels.txt");   // 23.7  MB File
         out = new FileOutputStream("output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }



        s.stop();
        System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
    }
}

[Elapsed Time for Byte Stream Reader][1]

**Character Stream Reader Elapsed Time for 23.7 MB is 3 secs**

import Java.io.*;
import Java.io.IOException;
import Java.util.Scanner;

class ElaspedTimetoCopyAFileUsingCharacterStream
{

    private long startTime = 0;
    private long stopTime = 0;
    private boolean running = false;


    public void start() 
    {
        this.startTime = System.currentTimeMillis();
        this.running = true;
    }


    public void stop() 
    {
        this.stopTime = System.currentTimeMillis();
        this.running = false;
    }



    public long getElapsedTime() 
    {
        long elapsed;
        if (running) {
             elapsed = (System.currentTimeMillis() - startTime);
        }
        else {
            elapsed = (stopTime - startTime);
        }
        return elapsed;
    }



    public long getElapsedTimeSecs()                 
    {
        long elapsed;
        if (running) 
        {
            elapsed = ((System.currentTimeMillis() - startTime) / 1000);
        }
        else
        {
            elapsed = ((stopTime - startTime) / 1000);
        }
        return elapsed;
    }





    public static void main(String[] args) throws IOException
    {
        ElaspedTimetoCopyAFileUsingCharacterStream  s = new ElaspedTimetoCopyAFileUsingCharacterStream();
        s.start();

         FileReader in = null;                // CharacterStream Reader
      FileWriter out = null;

      try {
         in = new FileReader("vowels.txt");    // 23.7 MB
         out = new FileWriter("output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }

              s.stop();
        System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
    }
}


[Elapsed Time for Character Stream Reader][2]


  [1]: https://i.stack.imgur.com/hYo8y.png
  [2]: https://i.stack.imgur.com/xPjCK.png
1
Shiva Sagan

Utilisez ceci:

SimpleDateFormat format = new SimpleDateFormat("HH:mm");

Date d1 = format.parse(strStartTime);
Date d2 = format.parse(strEndTime);

long diff = d2.getTime() - d1.getTime();
long diffSeconds,diffMinutes,diffHours;

if (diff > 0) {
diffSeconds = diff / 1000 % 60;
diffMinutes = diff / (60 * 1000) % 60;
diffHours = diff / (60 * 60 * 1000);
}
else{
long diffpos = (24*((60 * 60 * 1000))) + diff;
diffSeconds = diffpos / 1000 % 60;
diffMinutes = diffpos / (60 * 1000) % 60;
diffHours = (diffpos / (60 * 60 * 1000));
}

(En outre, il est important que, par exemple, l'heure de début soit 23h00 et l'heure de fin 1h00 pour obtenir une durée de 2h00.)

la partie "else" peut le corriger

0
N. N

J'ai construit une fonction de formatage basée sur des choses que j'ai volées de SO. J'avais besoin d'un moyen de "profiler" les choses dans les messages du journal, donc j'avais besoin d'un message de durée fixe.

public static String GetElapsed(long aInitialTime, long aEndTime, boolean aIncludeMillis)
{
  StringBuffer elapsed = new StringBuffer();

  Map<String, Long> units = new HashMap<String, Long>();

  long milliseconds = aEndTime - aInitialTime;

  long seconds = milliseconds / 1000;
  long minutes = milliseconds / (60 * 1000);
  long hours = milliseconds / (60 * 60 * 1000);
  long days = milliseconds / (24 * 60 * 60 * 1000);

  units.put("milliseconds", milliseconds);
  units.put("seconds", seconds);
  units.put("minutes", minutes);
  units.put("hours", hours);
  units.put("days", days);

  if (days > 0)
  {
    long leftoverHours = hours % 24;
    units.put("hours", leftoverHours);
  }

  if (hours > 0)
  {
    long leftoeverMinutes = minutes % 60;
    units.put("minutes", leftoeverMinutes);
  }

  if (minutes > 0)
  {
    long leftoverSeconds = seconds % 60;
    units.put("seconds", leftoverSeconds);
  }

  if (seconds > 0)
  {
    long leftoverMilliseconds = milliseconds % 1000;
    units.put("milliseconds", leftoverMilliseconds);
  }

  elapsed.append(PrependZeroIfNeeded(units.get("days")) + " days ")
      .append(PrependZeroIfNeeded(units.get("hours")) + " hours ")
      .append(PrependZeroIfNeeded(units.get("minutes")) + " minutes ")
      .append(PrependZeroIfNeeded(units.get("seconds")) + " seconds ")
      .append(PrependZeroIfNeeded(units.get("milliseconds")) + " ms");

  return elapsed.toString();

}

private static String PrependZeroIfNeeded(long aValue)
{
  return aValue < 10 ? "0" + aValue : Long.toString(aValue);
}

Et une classe de test:

import Java.util.Calendar;
import Java.util.Date;
import Java.util.GregorianCalendar;

import junit.framework.TestCase;

public class TimeUtilsTest extends TestCase
{

  public void testGetElapsed()
  {
    long start = System.currentTimeMillis();
    GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance();
    calendar.setTime(new Date(start));

    calendar.add(Calendar.MILLISECOND, 610);
    calendar.add(Calendar.SECOND, 35);
    calendar.add(Calendar.MINUTE, 5);
    calendar.add(Calendar.DAY_OF_YEAR, 5);

    long end = calendar.getTimeInMillis();

    assertEquals("05 days 00 hours 05 minutes 35 seconds 610 ms", TimeUtils.GetElapsed(start, end, true));

  }

}
0
Buffalo

j'ai trouvé ce code utile pour chronométrer les choses:

public class Et {
    public Et() {
    reset();
    }
    public void reset() {
    t0=System.nanoTime();
    }
    public long t0() {
        return t0;
    }
    public long dt() {
        return System.nanoTime()-t0();
    }
    public double etms() {
    return etms(dt());
    }
    @Override public String toString() {
        return etms()+" ms.";
    }
    public static double etms(long dt) {
        return dt/1000000.; // 1_000_000. breaks cobertura
    }
    private Long t0;
}
0
Ray Tayek