-2

There seems to be no easy answer in stackoverflow for this problem. I simply want to get the difference between two Calendar instances and display in HH:mm:ss.SSS

So far, I have

SimpleDateFormat dateFormat = new                      
  SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");           
  Calendar start = Calendar.getInstance();               
  say("start time:"+dateFormat.format(start.getTime())); 

and

 Calendar ending = Calendar.getInstance();              
  say("ending time:"+dateFormat.format(ending.getTime()));
 long milli = ending.getTime().getTime()      
             - start.getTime().getTime();     
 long sec = milli / 1000; // millisec to sec  
 say("elapsed time: " + sec + "." + milli );  

which does work to display the two times.

 start time: 2018-03-02 15:44:41.194  
*** program runs ***
 ending time:2018-03-02 15:44:41.198 
 elapsed time: 0.4                   

But shouldn't it be saying 0.004 seconds?

And PLEASE no JodaTime answers. This shop does not support that.

Baruch Atta
  • 421
  • 1
  • 5
  • 16

4 Answers4

1
    Instant start = Instant.now();

And

    Instant end = Instant.now();
    long milli = ChronoUnit.MILLIS.between(start, end);
    System.out.format(Locale.ENGLISH, "elapsed time: %.3f%n", milli / 1000.0);

On my computer this printed

elapsed time: 0.004

Formatting with String.format or System.out.format() also works with your way of measuring the milliseconds, of course.

Using Java 9 you can (at least on some computers) have more decimals if you want:

    System.out.println("elapsed time: " 
            +  ChronoUnit.NANOS.between(start, end) / (double) TimeUnit.SECONDS.toNanos(1));

I got

elapsed time: 0.003739

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

I wrote a little function for you, it returns a number as a string filled with as many "0" as you want.

public String getStringNumber(long number, int displaySize) {
    String str = new String();
    int length = String.valueOf(number).length();
    while (length++ < displaySize)
        str += "0";
    str += number;
    return str;
}

Now you can just replace in your code

say("elapsed time: " + sec + "." + getStringNumber(milli, 4));
Mickael B.
  • 4,755
  • 4
  • 24
  • 48
  • Thanks - this works for me. Just make the milliseconds (milli, 3). So this is Java? In COBOL I could do this in ZERO lines of code. Oh well. – Baruch Atta Mar 02 '18 at 21:31
  • 2
    @BaruchAtta Technically, in Java, you can do in one `String.format("%05d", yournumber);`, but a quick google of "java zero pad string" would have told you that ;) – MadProgrammer Mar 02 '18 at 22:25
  • I'm removing your answer as a solution because it displays 77 seconds and 213 milliseconds as 77213. Not the correct answer. I would be looking for 77.213 with the decimal in the correct place. – Baruch Atta Mar 05 '18 at 17:04
  • Well, that's not what you asked for, then you have to `say("elapsed time: " +getStringNumber(sec, 2) + "." + getStringNumber(milli, 3));` – Mickael B. Mar 05 '18 at 17:20
  • I asked for " display in HH:mm:ss.SSS". Thanks for trying. – Baruch Atta Mar 05 '18 at 20:11
  • @MadProgrammer Sorry no dice. Your solution does not work. String number = "1000543210"; long yournumber = Long.parseLong(number); say(String.format("%05d", yournumber)); which is your solution, displays as this: 1000543210 which is not HH:mm:ss.SSS – Baruch Atta Mar 05 '18 at 20:21
  • @BaruchAtta No kidding it's not going to work, because that's not how I it should be used. You want to pad a single element (like the seconds), then the above will work just fine – MadProgrammer Mar 05 '18 at 20:34
  • @BaruchAtta just use it like that `String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, microseconds)` where `hours` is for hours, `minutes` is for minutes, `seconds` is for seconds and `microseconds` is for microseconds. This whay you should have your _HH:mm:ss.SSS_ – Mickael B. Mar 05 '18 at 20:43
0

I finally arrived on this solution. It is awkward and not very elegant, but it works.

Calendar ending = Calendar.getInstance();
say("ending time:"+dateFormat.format(ending.getTime()));

long milli = ending.getTime().getTime()
- start.getTime().getTime();

long hrs = TimeUnit.MILLISECONDS.toHours(milli) % 24;
long min = TimeUnit.MILLISECONDS.toMinutes(milli) % 60;
long sec = TimeUnit.MILLISECONDS.toSeconds(milli) % 60;
long mls = milli % 1000;
String elaps = String.format("%02d:%02d:%02d.%03d", hrs,
min, sec, mls);

say("Elapsed time: " + elaps);

Here is the explanation: I convert the two Calendar variables to long, and subtract. Then I format the Long to a string in format hh:mm:ss.SSS which is what I wanted in the first place.

Here is the output

ending time:2018-03-05 15:07:17.923
Elapsed time: 00:01:15.964

Baruch Atta
  • 421
  • 1
  • 5
  • 16
  • Looking at this solution again, it is so surprising. TimeUnit.MILLISECONDS.toHours(milli) should return an integer. Or does it have that option also? – Baruch Atta Mar 05 '18 at 20:53
0

Okay, so, simply off the top of my head, without trying to perform anything kind of fancy, you could make use of the Java 8 date/time API, which provides the capability to calculate the different between two points in time.

So, taking your input, and running it through the code below, it outputs

2018-03-02T15:44:41.194
2018-03-02T15:44:41.198
0.004

Now, personally, I'd take the concept and simply create a DurationFormatter which could take a Duration and spit out your required format, but the idea here is to give you a jumping point to start from.

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Test {

    public static void main(String[] args) {
        String startTime = "2018-03-02 15:44:41.194";
        String endTime = "2018-03-02 15:44:41.198";

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

        LocalDateTime startDateTime = LocalDateTime.parse(startTime, formatter);
        LocalDateTime endDateTime = LocalDateTime.parse(endTime, formatter);

        System.out.println(startDateTime);
        System.out.println(endDateTime);

        Duration duration = Duration.between(startDateTime, endDateTime);

        long hours = duration.toHours();
        duration = duration.minusHours(hours);
        long mins = duration.toMinutes();
        duration = duration.minusMinutes(mins);
        long secs = duration.getSeconds();
        duration = duration.minusSeconds(secs);
        long millis = duration.toMillis();

        StringBuilder sb = new StringBuilder(12);
        if (hours > 0) {
            sb.append(pad(hours, 2));
        }
        if (mins == 0 && sb.length() > 0) {
            sb.append(":00");
        } else if (mins > 0) {
            if (hours > 0) {
                sb.append(":");
            }
            sb.append(pad(mins, 2));
        }
        if (secs == 0 & sb.length() > 0) {
            sb.append(":00");
        } else if (secs > 0) {
            if (mins > 0) {
                sb.append(":");
            }
            sb.append(pad(secs, 2));
        }
        if (millis == 0 & sb.length() > 0) {
            sb.append(".00");
        } else if (millis > 0) {
            if (secs > 0 || sb.length() > 0) {
                sb.append(".");
            } else if (sb.length() == 0) {
                sb.append("0.");
            }
            sb.append(pad(millis, 3));
        }

        System.out.println(sb.toString());
    }

    public static String pad(long value, long length) {
        return String.format("%0" + length + "d", value);
    }

}

Now, if we change the input to something like...

String startTime = "2018-03-02 15:44:41.194";
String endTime = "2018-03-08 15:44:41.198";

It outputs

144:00:00.004

Or if we use

String startTime = "2018-03-02 15:44:41.194";
String endTime = "2018-03-08 15:15:41.198";

It outputs

143:31:00.004

Or

String startTime = "2018-03-02 15:44:41.194";
String endTime = "2018-03-08 15:15:50.198";

It outputs

143:31:09.004

Or

2018-03-02T15:44:41.194
2018-03-02T15:50:41.194

It outputs

06:00.00

... to me, this is where it gets weird, technically it's correct (6 mins), but from the format, it's hard to deduce exactly what it means

This is where I might be tempted to use something more like String.format("%02d:%02d:%02d.%04d", hours, mins, secs, millis) which will output 00:06:00.0000, but that all comes do to you needs. You will need to decide how best to take the raw information and present it based on your needs, but there are a couple of different ideas

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • if I say that I like your answer, will you remove your downvote on my question? You must have put in a lot of time on this answer. shows a lot of work. The reason that I used Calendar class was because the last time that I checked, Date class was depreciated. Now we have this LocalDateTime class and Duration class. Where does it all end???? This "DATE" and time handling seems to change with each new release of Java. BTW my solution has six lines. Your solution has maybe a hundred. Or fifty. You get an A for effort but a C for elegance. Thanks for looking. – Baruch Atta Mar 06 '18 at 17:47
  • @BaruchAtta First, I’ve not downvote your question, trust me, if I had, you’d know. Second, that’s now SO works. Third, yes I can be confusing coming into the API a new, it was bad enough when they only had Date and Calendar. The date/time apis are a replacement for both Date/Calendar. Actually, my core answer only has 14 lines (if we assume you don’t want a variable format) and it could be reduced, but I’ll always prefer readability over “elegance”, but from the sounds of things, you’re never going t be satisfied – MadProgrammer Mar 06 '18 at 18:36
  • @BaruchAtta You also have to recognise that date/time manipulation is much more complex then simply subtracting two points in time, while over a short period it might not cause a “large” issue, the larger the range, the more troublesome it comes. In the end, any answer that uses simple arithmetic is just wrong and becomes more problematic the more you rely in the accuracy of the result (even just down to the second level). This is why libraries like JodaTime and the new date/time APis exist – MadProgrammer Mar 06 '18 at 18:40