Calculate Elapsed/Execution Time in Java

Wonder on how long your function is get executed? How you measure elapsed time in Java? In this article, we’ll explore several ways to measure elapsed time.

System.currentTimeMillis()

  • static long currentTimeMillis(): Part of Class System, returns the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
ElapsedTimeCurrentTimeMillis.java
import java.util.concurrent.TimeUnit;

public class ElapsedTimeCurrentTimeMillis {

     static void doSomething() {
         try {
             // Sleep 3 seconds
             TimeUnit.SECONDS.sleep(3);
         } catch (InterruptedException ex) {
             System.out.println("InterruptedException occured: " + ex.getMessage());
         }
    }

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        doSomething();
        long endTime = System.currentTimeMillis();

        // calculate time difference
        long timeDiff = endTime - startTime;
        System.out.println("Elapsed time in milliseconds: " + timeDiff);
    }
}
                    

Output (may vary):

Elapsed time in milliseconds: 3002

Be aware that System.currentTimeMillis() has a pretty bad resolution:

  • if the measurement error should be < ±1 ms, it fails for all tasks < 200 ms
  • in reality, the resolution varies between 10 and 100 ms
  • it's a wall-clock time!

System.nanoTime()

  • static long nanoTime(): Part of Class System, returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds.

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.

ElapsedTimeNanoTime.java
import java.util.concurrent.TimeUnit;

public class ElapsedTimeNanoTime {

     static void doSomething() {
         // Sleep 3 seconds - purposely truncated         
    }

    public static void main(String[] args) {
        long startTime = System.nanoTime();
        doSomething();
        long endTime = System.nanoTime();

        // calculate time difference
        long timeDiff = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
        System.out.println("Elapsed time in milliseconds: " + timeDiff);
    }
}
                    

Output (may vary):

Elapsed time in milliseconds: 3002

System.nanoTime() has a better resolution:

  • it should never be worse than System.currentTimeMillis()
  • depending on the hardware and OS it can deliver accuracy in the microsecond range

Because of those reasons, this is the most recommended solution to measure elapsed time in Java.

Date.getTime()

  • long getTime(): Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.
ElapsedTimeDateGetTime.java
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class ElapsedTimeDateGetTime {

    static void doSomething() {
         // Sleep 3 seconds - purposely truncated         
    }

    public static void main(String[] args) {
        long startTime = new Date().getTime();
        doSomething();
        long endTime = new Date().getTime();

        // calculate time difference
        long timeDiff = endTime - startTime;
        System.out.println("Elapsed time in milliseconds: " + timeDiff);
    }
}
                    

Output (may vary):

Elapsed time in milliseconds: 3002

Java 8 - Using Instant and Duration

  • Instant: Represents an instant in time on the time line. In Java 8 the Instant class represents an instant in time represented by a number of seconds and a number of nanoseconds since Jan. 1st 1970.
  • Duration: Represents a duration of time, for instance the time between two instants. Like the Instant class a Duration represents its time as a number of seconds and nanoseconds.
ElapsedTimeInstantDuration.java
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;

public class ElapsedTimeInstantDuration {

    static void doSomething() {
         // Sleep 3 seconds - purposely truncated         
    }

    public static void main(String[] args) {
        Instant instantStart = Instant.now();
        long startTime = instantStart.toEpochMilli();
        
        doSomething();
        
        Instant instantEnd = Instant.now();
        long endTime = instantEnd.toEpochMilli();

        // calculate time difference
        long timeDiff = endTime - startTime;
        System.out.println("toEpochMilli - Elapsed time in ms: " + timeDiff);
        
        long timeElapsed = Duration.between(instantStart, instantEnd).toMillis();
        System.out.println("Duration - Elapsed time in ms: " + timeElapsed);
    }
}
                    

Output (may vary):

toEpochMilli - Elapsed time in ms: 3001 Duration - Elapsed time in ms: 3001

Joda-Time Instant and Duration

  • Instant: Represents an exact point in time in milliseconds from the Java epoch of 1970-01-01T00:00:00Z
  • Duration: Represents the duration in milliseconds between 2 points in time

You need to add Joda-Time dependency, as example if you are using maven:

<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.2</version>
</dependency>
                    

import java.util.concurrent.TimeUnit;
import org.joda.time.Duration;
import org.joda.time.Instant;

public class ElapsedTimeJodaInstantDuration {

    static void doSomething() {
         // Sleep 3 seconds - purposely truncated         
    }

    public static void main(String[] args) {
        Instant instantStart = Instant.now();
        long startTime = instantStart.getMillis();
        
        doSomething();
        
        Instant instantEnd = Instant.now();
        long endTime = instantEnd.getMillis();

        // calculate time difference
        long timeDiff = endTime - startTime;
        System.out.println("getMillis - Elapsed time in ms: " + timeDiff);
        
        long timeElapsed = new Duration(instantStart, instantEnd).getMillis();
        System.out.println("Duration - Elapsed time in ms: " + timeElapsed);
    }
}
                    

Output (may vary):

getMillis - Elapsed time in ms: 3001 Duration - Elapsed time in ms: 3001

As rule of thumb, if your Java version is Java 8 and above, you should Date/Time Standard Java Library instead of using Joda-Time library.

Many open source Java libraries like Apache Commons Lang, Google Guava and Spring also provides "StopWatch" utility class which can be used to measure elapsed time in Java. StopWatch improves readability to minimize calculation error while calculating elapsed execution time but beware that StopWatch is not thread safe and should not be shared in multi-threading environment.

Apache Commons Lang Stopwatch

StopWatch provides a convenient API for timings.

To start the watch, call start() or createStarted(). At this point you can:

  • split() the watch to get the time whilst the watch continues in the background. unsplit() will remove the effect of the split. At this point, these three options are available again.
  • suspend() the watch to pause it. resume() allows the watch to continue. Any time between the suspend and resume will not be counted in the total. At this point, these three options are available again.
  • stop() the watch to complete the timing session.

It is intended that the output methods toString() and getTime() should only be called after stop, split or suspend, however a suitable result will be returned at other points.

This class is not thread-safe

You need to add dependency for Apache Commons Lang, like if you using maven:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.8.1</version>
</dependency>
                    

ElapsedTimeApacheStopWatch.java
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.time.StopWatch;

public class ElapsedTimeApacheStopWatch {

     static void doSomething() {
         try {
             // Sleep 2 seconds
             TimeUnit.SECONDS.sleep(2);
         } catch (InterruptedException ex) {
             System.out.println("InterruptedException occured: " + ex.getMessage());
         }
    }

    public static void main(String[] args) {
        StopWatch sWatch = new StopWatch();
        
        sWatch.start();
        doSomething();
        
        sWatch.suspend();
        doSomething();
        
        sWatch.resume();
        doSomething();
        
        sWatch.stop();

        System.out.println("Elapsed time in milliseconds: " + sWatch.getTime());
    }
}
                    

Output (may vary):

Elapsed time in milliseconds: 4001

Google Guava StopWatch

We can also measure elapsed time using Guava’s Stopwatch. Stopwatch measures elapsed time in nanoseconds. It is useful to measure elapsed time using this class instead of direct calls to System.nanoTime() for a few reasons:

  • An alternate time source can be substituted, for testing or performance reasons.
  • As documented by nanoTime, the value returned has no absolute meaning, and can only be interpreted as relative to another timestamp returned by nanoTime at a different time. Stopwatch is a more effective abstraction because it exposes only these relative values, not the absolute ones.

Note: This class is not thread-safe.

Add maven dependency for Guava:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>27.0.1-jre</version>
</dependency>
                    

ElapsedTimeGuavaStopwatch.java
import com.google.common.base.Stopwatch;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

public class ElapsedTimeGuavaStopwatch {

    static void doSomething() {
         // Sleep 3 seconds - purposely truncated         
    }

    public static void main(String[] args) {
        Stopwatch swatch = Stopwatch.createStarted();
        doSomething();        
        swatch.stop();

        Duration duration = swatch.elapsed();
        System.out.println("Elapsed time in milliseconds: " + duration.toMillis());
    }
}
                    

Output (may vary):

Elapsed time in milliseconds: 3001

Or, if you still using Java 7, the program need to change a bit. First, we need to "downgrade" Guava version

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>
                    

And change the elapsed(...) function to return instead:

Stopwatch swatch = Stopwatch.createStarted();
doSomething();        
swatch.stop();

long duration = swatch.elapsed(TimeUnit.MILLISECONDS);
System.out.println("Elapsed time in milliseconds: " + duration);
                    

Spring StopWatch

StopWatch allowing for timing of a number of tasks, exposing total running time and running time for each named task. Conceals use of System.currentTimeMillis(), improving the readability of application code and reducing the likelihood of calculation errors.

Note that this object is not designed to be thread-safe and does not use synchronization.

This class is normally used to verify performance during proof-of-concepts and in development, rather than as part of production applications.

Add dependency for Spring Core:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.1.2.RELEASE</version>
</dependency>
                    

ElapsedTimeSpringStopWatch.java
import java.util.concurrent.TimeUnit;
import org.springframework.util.StopWatch;

public class ElapsedTimeSpringStopWatch {

     static void doSomething() {
         // Sleep 2 seconds - purposely truncated         
    }

    public static void main(String[] args) {
        StopWatch sWatch = new StopWatch("Spring StopWatch Test");
        
        sWatch.start("Task #1");
        doSomething();        
        sWatch.stop();

        sWatch.start("Task #2");
        doSomething();        
        sWatch.stop();

        // getTotalTimeMillis(): Return the total time in milliseconds for all tasks.
        System.out.println("Elapsed time in milliseconds: " + sWatch.getTotalTimeMillis());
        
        // prettyPrint(): Return a string with a table describing all tasks performed.
        System.out.println("Pretty Print: " + sWatch.prettyPrint());

        // shortSummary(): Return a short description of the total running time.
        System.out.println("Short Summary: " + sWatch.shortSummary());

        // getTaskCount(): Return the number of tasks timed.
        System.out.println("Total Task Count: " + sWatch.getTaskCount());

        // getLastTaskName(): Return the name of the last task.
        System.out.println("Last Task Name: " + sWatch.getLastTaskName());
    }
}
                    

Output (may vary):

Elapsed time in milliseconds: 4002 Pretty Print: StopWatch 'Spring StopWatch Test': running time (millis) = 4002 ----------------------------------------- ms % Task name ----------------------------------------- 02002 050% Task #1 02000 050% Task #2 Short Summary: StopWatch 'Spring StopWatch Test': running time (millis) = 4002 Total Task Count: 2 Last Task Name: Task #2

What I like here is, Spring StopWatch provides prettyPrint() to return a string with a table describing all tasks performed, which is can be handy in test environment.

Or, if you still using Java 7, we also need to "downgrade" Spring version

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.3.25.RELEASE</version>
</dependency>
                    

And the program above will able to run without any change. Only when you try to download the library in maven central, you may encounter error: Received fatal alert: protocol_version

You need to enable TLS 1.2 protocol with Java property in the command line:

mvn -Dhttps.protocols=TLSv1.2 install

Conclusion

There are standard Java classes and external packages that provide functionality that provides many ways to measure elapsed time in Java:

  • Simple measurement, using System.currentTimeMillis() or System.nanoTime() or Date.getTime().
  • Java 8, using Instant and Duration.
  • If using Joda-Time, you also can use Instant and Duration from the library. Use Joda-Time if your Java version is prior to Java 8.
  • Using "StopWatch" utilility from Apache Commons Lang, Guava, or Spring

The most recommended way is to use System.nanoTime(). Guava's StopWatch is useful to measure elapsed time instead of direct calls to System.nanoTime().

However, that for proper benchmarking, simple time measurement (event manual measurement) is not sufficient. You need more proper tools or framework for benchmarking.