How do I measure time elapsed in Java? [duplicate]
Asked Answered
H

15

361

I want to have something like this:

public class Stream
{
    public startTime;
    public endTime;

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

Also it is important that for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.

Which types to use in order to accomplish this in Java?

Hypermetropia answered 20/11, 2009 at 11:51 Comment(2)
Possible duplicates: stackoverflow.com/questions/180158, stackoverflow.com/questions/567659 and stackoverflow.com/questions/503877.Cot
The linked Question is not a duplicate. That question’s title is misleading. That question’s content is about accessing the current time from the computer clock. The answers involve ` System.currentTimeMillis()` and System.nanoTime(). This question here is focused on calculating elapsed time between two moments without regard to fetching the current time.Tetratomic
T
712

Unfortunately, none of the ten answers posted so far are quite right.

If you are measuring elapsed time, and you want it to be correct, you must use System.nanoTime(). You cannot use System.currentTimeMillis(), unless you don't mind your result being wrong.

The purpose of nanoTime is to measure elapsed time, and the purpose of currentTimeMillis is to measure wall-clock time. You can't use the one for the other purpose. The reason is that no computer's clock is perfect; it always drifts and occasionally needs to be corrected. This correction might either happen manually, or in the case of most machines, there's a process that runs and continually issues small corrections to the system clock ("wall clock"). These tend to happen often. Another such correction happens whenever there is a leap second.

Since nanoTime's purpose is to measure elapsed time, it is unaffected by any of these small corrections. It is what you want to use. Any timings currently underway with currentTimeMillis will be off -- possibly even negative.

You may say, "this doesn't sound like it would ever really matter that much," to which I say, maybe not, but overall, isn't correct code just better than incorrect code? Besides, nanoTime is shorter to type anyway.

Previously posted disclaimers about nanoTime usually having only microsecond precision are valid. Also it can take more than a whole microsecond to invoke, depending on circumstances (as can the other one), so don't expect to time very very small intervals correctly.

Texas answered 21/11, 2009 at 17:7 Comment(15)
actually i need to measure durations of minutes or sometimes even almost an hour, something like that, are there any performance issues, between nanotime and currentmiliseconds ?Hypermetropia
be wary of nanoTime in multi-core environmentsTravesty
@Travesty can you clarify?Quadrivalent
@Quadrivalent - sure; basically some implementations of nanoTime on some versions of OS/Java/CPU will use hardware CPU time stamp counter (TSC) . However this TSC may not be the same between cores/processors. If your thread is rescheduled to a different core partway through, you will end up with a start timestamp from core 1 and a end timestamp from core 2 but they might not be the same time (you can even get negative values) - some examples: #510962 is a good eTravesty
@jasonk, this is a fairly dated problem but the fact is that while the accuracy of the TSC can be affected by multithreading, cpu throttling, and the phase of the moon, there is no other way to get this type of accuracy and precision on a standard pc configuration. its best to just use it and understand the bounds on the error which is usually very small!Instil
@Instil yes, totally right - use it, and hence just be wary of its misleading responses. Easy approach would be to average results over a large set of runs.Travesty
If I want the result of the elapsed time in milliseconds, I need to multiply by 1000000, right?Velites
@YuvalA. NO! Never do that! Don't even divide by 1000000 either (which is at least correct in concept). Always use a library, such as the JDK's TimeUnit.NANOSECONDS.toMillis(value).Texas
@KevinBourrillion Why shouldn't we divide or multiply elapsed time to change units?Surfboat
Because it is senselessly error-prone (as the comment illustrates) and harder to read.Texas
@KevinBourrillion TimeUnit.NANOSECONDS.toMillis(value) seems to have the unfortunate side effect of rounding. That's not such a big deal, but for toSeconds() or higher, you're losing a lot of precision. x/1000.0/1000.0/1000.0 works for converting to seconds, and is very clear.Tumer
Dividing by 1.0e9 is far shorter and requires no counting of zeroes.Dictator
@ChinotoVokro And it might be more accurate, as this test shows.Desiccator
How about Duration.ofNanos(nanoTime).toMillis() ? Does this have an accuracy problem too?Covariance
I actually saw ugly over-engineered code with TimeUnit & Duration & Decimal manipulations, I prefer to see value / 1000.0 instead. Same with Objects.isEmpty for non-collection objects.Perversity
V
238

Which types to use in order to accomplish this in Java?

The short answer is a long. Now, more on how to measure...

System.currentTimeMillis()

The "traditional" way to do this is indeed to use System.currentTimeMillis():

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

o.a.c.l.t.StopWatch

Note that Commons Lang has a StopWatch class that can be used to measure execution time in milliseconds. It has methods methods like split(), suspend(), resume(), etc that allow to take measure at different points of the execution and that you may find convenient. Have a look at it.

System.nanoTime()

You may prefer to use System.nanoTime() if you are looking for extremely precise measurements of elapsed time. From its javadoc:

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

Jamon

Another option would be to use JAMon, a tool that gathers statistics (execution time, number of hit, average execution time, min, max, etc) for any code that comes between start() and stop() methods. Below, a very simple example:

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

Check out this article on www.javaperformancetunning.com for a nice introduction.

Using AOP

Finally, if you don't want to clutter your code with these measurement (or if you can't change existing code), then AOP would be a perfect weapon. I'm not going to discuss this very deeply but I wanted at least to mention it.

Below, a very simple aspect using AspectJ and JAMon (here, the short name of the pointcut will be used for the JAMon monitor, hence the call to 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;
    }
}

The pointcut definition could be easily adapted to monitor any method based on the class name, the package name, the method name, or any combination of these. Measurement is really a perfect use case for AOP.

Vigilance answered 20/11, 2009 at 13:38 Comment(0)
O
42

Your new class:

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

Afterwards, the time passed can be converted to whatever format you like, with a calender for example

Greetz, GHad

Orelia answered 20/11, 2009 at 11:58 Comment(4)
+1 for the TimeUnit mention. I didn't knew it existed ( why it is not in `java.util' package? )Apoplexy
@Oscar Maybe Mr. Lea did consider it was part of the concurrent APIVigilance
TimeUnit is there since Java 1.5, but has been extended in Java 1.6. It's a very helpfull enum to work withOrelia
Great idea creating that class. Kudos!Photofluorography
T
24

tl;dr

for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.

Not possible. If you have only time-of-day, the clock stops at midnight. Without the context of dates, how do we know if you mean 1 AM on the next day, next week, or next decade?

So going from 11 PM to 1 AM means moving backwards in time 22 hours, running the hands of the clock counterclockwise. See the result below, a negative twenty-two hours.

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

Crossing midnight requires the larger context of date in addition to time-of-day (see below).

How do I measure time elapsed in Java?

  1. Capture the current moment in UTC, with Instant.now().
  2. Capture another such moment later.
  3. Pass both to Duration.between.
  4. (a) From the resulting Duration object, extract a number of 24-hour days, hours, minutes, seconds, and fractional second in nanoseconds by calling the various to…Part methods.
    (b) Or, call toString to generate a String in standard ISO 8601 format of PnYnMnDTnHnMnS.

Example code, using pair of Instant objects.

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

New Technology In Java 8+

We have new technology for this now built into Java 8 and later, the java.time framework.

java.time

The java.time framework is defined by JSR 310, inspired by the highly successful Joda-Time project, extended by the ThreeTen-Extra project, and described in the Oracle Tutorial.

The old date-time classes such as java.util.Date/.Calendar bundled with the earliest versions of Java have proven to be poorly designed, confusing, and troublesome. They are supplanted by the java.time classes.

Resolution

Other answers discuss resolution.

The java.time classes have nanosecond resolution, up to nine digits of a decimal fraction of a second. For example, 2016-03-12T04:29:39.123456789Z.

Both the old java.util.Date/.Calendar classes and the Joda-Time classes have millisecond resolution (3 digits of fraction). For example, 2016-03-12T04:29:39.123Z.

In Java 8, the current moment is fetched with up to only millisecond resolution because of a legacy issue. In Java 9 and later, the current time can be determined up to nanosecond resolution provided your computer’s hardware clock runs so finely.

Time-Of-Day

If you truly want to work with only the time-of-day lacking any date or time zone, use the LocalTime class.

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

A Duration represents a span of time it terms of a count of seconds plus nanoseconds.

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

Dump to console.

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

sooner: 17:00 | later: 19:00 | duration: PT2H

ISO 8601

Notice the default output of Duration::toString is in standard ISO 8601 format. In this format, the P marks the beginning (as in 'Period'), and the T separates any years-months-days portion from the hours-minutes-seconds portion.

Crossing Midnight

Unfortunately, working with time-of-day only gets tricky when you wrap around the clock crossing midnight. The LocalTime class handles this by assuming you want to go backwards to an earlier point in the day.

Using the same code as above but going from 23:00 to 01:00 results in a negative twenty-two hours (PT-22H).

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

sooner: 23:00 | later: 01:00 | duration: PT-22H

Date-Time

If you intend to cross midnight, it probably makes sense for you to be working with date-time values rather than time-of-day-only values.

Time Zone

Time zone is crucial to dates. So we specify three items: (1) the desired date, (2) desired time-of-day, and (3) the time zone as a context by which to interpret that date and time. Here we arbitrarily choose the time zone of the Montréal area.

If you define the date by only an offset-from-UTC, use a ZoneOffset with a OffsetDateTime. If you have a full time zone (offset plus rules for handling anomalies such as Daylight Saving Time), use a ZoneId with a ZonedDateTime.

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

We specify the later time as next day at 1:00 AM.

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

We calculate the Duration in the same manner as seen above. Now we get the two hours expected by this Question.

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

Dump to console.

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

sooner: 2016-01-23T23:00-05:00[America/Montreal] | later: 2016-01-24T01:00-05:00[America/Montreal] | duration: PT2H

Daylight Saving Time

If the date-times at hand had involved Daylight Saving Time (DST) or other such anomaly, the java.time classes would adjust as needed. Read class doc for details.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Tetratomic answered 16/3, 2016 at 23:5 Comment(5)
this answer looks like a mostly copy-paste of - #32438050 and while it does mention time, doesn't answer the questionAutoradiograph
@Autoradiograph I suggest you re-read more closely. As for copy-paste, that linked Answer has no section on resolution, no discussion of Duration, and no explanation of anomalies such as Daylight Saving Time being ignored by a time-of-day-only calculation. As for not addressing the Question here, I would say Duration.between ( sooner, later ) combined with an explanation of the problem of rolling over midnight is a spot-on answer to asking "if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00". While I appreciate constructive criticism, I expect more diligence.Tetratomic
I've followed your suggestion and re-read the answer more closely. It does answer the question. I've jumped to conclusion too soon by reading first 2-3 paragraphs and not finding a lot of connection with the question. That's my mistake, I apologize for my previous comment. I wonder if a constructive comment here would be: The answer can be improved by restructuring it in a way that it starts from the asked question itself. The paragraphs could be formed in descending order of abstraction, perhaps, starting from answering 'How to measure time elapsed' in general way and then going into detailsAutoradiograph
@Autoradiograph Apology accepted. Per your comment I added a "tl;dr" section up top that gets right to the point of the Question, with practical code examples of the wrong way and right way to calc elapsed time. Nice improvement to this Answer. Thanks for your suggestion.Tetratomic
Thank you for taking time to answer to my comments. I've learned a good lesson that a thesis that seems vague at first should not be rejected completely because it may actually contain valid points. This is probably somewhat general rule that people have to learn as they experience need of efficient communication.Autoradiograph
E
23

If the purpose is to simply print coarse timing information to your program logs, then the easy solution for Java projects is not to write your own stopwatch or timer classes, but just use the org.apache.commons.lang.time.StopWatch class that is part of 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);
Equivocal answered 20/11, 2009 at 14:21 Comment(4)
Most loggers also support timestamps as part of the logging output.Estonian
@James McMahon. Yes, but those timestamps show the current time, not the accumulated time of a given task.Equivocal
Note that StopWatch uses System.currentTimeMillis() in its implementation.Banna
System.currentTimeMillis() is for getStartTime() property only. Time calculations are entirely based on System.nanoTime() (at least in org.apache.commons.lang3 version)Extract
S
8

It is worth noting that

  • System.currentTimeMillis() has only millisecond accuracy at best. At worth its can be 16 ms on some windows systems. It has a lower cost that alternatives < 200 ns.
  • System.nanoTime() is only micro-second accurate on most systems and can jump on windows systems by 100 microseconds (i.e sometimes it not as accurate as it appears)
  • Calendar is a very expensive way to calculate time. (i can think of apart from XMLGregorianCalendar) Sometimes its the most appropriate solution but be aware you should only time long intervals.
Skyscape answered 20/11, 2009 at 23:0 Comment(2)
What is with 16ms and Windows? Windows reads the system clock every 16ms?Airspeed
@KorayTugay older versions of Windows uses a clock which ticked at 60 Hz or about every 16.7 ms. I think it was used to sample which keys were pressed on the keyboard as well.Skyscape
P
7

Java provides the static method System.currentTimeMillis(). And that's returning a long value, so it's a good reference. A lot of other classes accept a 'timeInMillis' parameter which is long as well.

And a lot of people find it easier to use the Joda Time library to do calculations on dates and times.

Papaw answered 20/11, 2009 at 11:55 Comment(3)
+1 for mentioning joda time. what happened to porting that into java proper? jsr310?Gonick
@Bedwyr: it is unfortunately still not finished. Maybe Java8.Darbydarce
@Darbydarce hmm - maybe they can find time for it now closures are in and it's all delayed.Gonick
A
6

Which types to use in order to accomplish this in Java?

Answer: 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. 

That's my direct answer for your first question.

For the last "note" I would suggest you to use Joda Time. It contains an interval class suitable for what you need.

Apoplexy answered 20/11, 2009 at 13:11 Comment(2)
System.currentTimeMillis() returns the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC. :) i guess i'm ok with this; i was afraid that I will have problems if start was yesterday and stop is today.Hypermetropia
Good to see @ChuckNorris using StackOverFlow.Hitch
E
3

If you prefer using Java's Calendar API you can try this,

Date startingTime = Calendar.getInstance().getTime();
//later on
Date now = Calendar.getInstance().getTime();
long timeElapsed = now.getTime() - startingTime.getTime();
Estonian answered 20/11, 2009 at 12:57 Comment(2)
Bad idea. It adds MUCH more overhead than only the time in millis. If you only need the time in millis, just use System.currentTimeMillis(), you don't need to know about the timezone and all that stuff which you see in Calendar#toString().Darbydarce
You may have a point. I don't know if that would ever have a measurable effect on performance, but it is probably good practice. However if you already have a Calendar object, or if you want to do more sophisticated manipulations that Calendar facilitates, then this approach may be valid.Estonian
E
3

If you are writing an application that must deal with durations of time, then please take a look at Joda-Time which has class specifically for handling Durations, Intervals, and Periods. Your getDuration() method looks like it could return a Joda-Time Interval:

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);
}
Equivocal answered 20/11, 2009 at 13:51 Comment(0)
S
3
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
Sierra answered 19/11, 2016 at 6:42 Comment(0)
W
1

If you're getting your timestamps from System.currentTimeMillis(), then your time variables should be longs.

Wadlinger answered 20/11, 2009 at 11:52 Comment(0)
P
0

i found this code to be useful when timing things:

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;
}
Phung answered 16/3, 2016 at 23:17 Comment(0)
E
0

Use this:

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

(Also it is important that for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.)

the "else" part can get it correct

Erythrism answered 21/4, 2016 at 20:0 Comment(0)
W
0

I built a formatting function based on stuff I stole off SO. I needed a way of "profiling" stuff in log messages, so I needed a fixed length duration message.

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

And a test class:

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

  }

}
Wheat answered 16/3, 2018 at 8:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.