1

Why the output of the Java code below is 04:18:23 and not 03:18:23?

public static void main(String[] args) {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    try {
        Date start = sdf.parse("00:44:16");
        Date end = sdf.parse("04:02:39");
        long duration = end.getTime() - start.getTime();
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(duration);
        System.out.println(sdf.format(cal.getTime()));
    } catch (ParseException e) {
        e.printStackTrace();
    }
}
Vlad
  • 844
  • 1
  • 12
  • 22

3 Answers3

10

Because that's not how you get a duration. Change your code to this:

package com.sandbox;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Sandbox {

    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        try {
            Date start = sdf.parse("00:44:16");
            Date end = sdf.parse("04:02:39");
            long duration = end.getTime() - start.getTime();
            Calendar cal = Calendar.getInstance();
            cal.setTimeInMillis(duration);
            System.out.println(new SimpleDateFormat("yyyy MM dd HH:mm:ss").format(cal.getTime()));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

You'll see it prints out 1969 12 31 19:18:23. That's a date not a duration. Since you're skipping the date components when you print out your answer, it appears like it's printing out a duration, but it's really not.

To be frank, I don't know how to do this in java. I just use the JodaTime library. There's a class called Duration that makes this easy. Here's a SO question that shows how to use it to print out the results any way you want: "pretty print" duration in java

Community
  • 1
  • 1
Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356
  • I copy-pasted your code and I get the following output: 1970 01 01 04:18:23 – Vlad Jun 05 '13 at 20:08
  • 1
    @Vlad probably because of a difference in our time zones. The difference we got is irrelevant to my point: You're printing out a date, not a duration. – Daniel Kaplan Jun 05 '13 at 20:09
  • @tieTYT If you set the timezone to UTC, it will print the expect result. It's a huge hack, but it would work if the difference is less than 24h. – NullUserException Jun 05 '13 at 20:11
  • Given that dates are represented as offset from 1/1/1970, the conceptual difference between a date and an interval is rather blurred. As it has been pointed out, in the GMT timezone this is the correct answer. – Nicola Musatti Jun 05 '13 at 20:20
  • @NicolaMusatti I don't feel comfortable with that. He coincidentally could get the correct answer if he switched the timezones and didn't print the date. But if he were testing with a difference in years, it wouldn't print the right thing. – Daniel Kaplan Jun 05 '13 at 20:25
  • I agree that it's better to use a library that does provide an explicit representation for intervals. Date arithmetic is indeed tricky. – Nicola Musatti Jun 05 '13 at 20:27
  • @tieTYT I preferred to use Date objects because I can format the output with SimpleDateFormat, which is quite nice in my opinion. – Vlad Jun 05 '13 at 20:58
  • @Vlad well it's called `SimpleDateFormat`, not `SimpleDurationFormat`. – Daniel Kaplan Jun 05 '13 at 21:00
3

Alternatively, if you don't want to use JodaTime, it's pretty simple to compute the hours, minutes, and seconds from a duration in milliseconds:

public static void main(String[] args) throws ParseException {
  SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
  Date start = sdf.parse("00:44:16");
  Date end = sdf.parse("04:02:39");
  long durationMs = end.getTime() - start.getTime();

  final int oneHourMs = 3600000;
  final int oneMinuteMs = 60000;
  final int oneSecondMs = 1000;

  long hours = durationMs / oneHourMs;
  long minutes = (durationMs % oneHourMs) / oneMinuteMs;
  long seconds = (durationMs % oneMinuteMs) / oneSecondMs;

  System.out.format("%02d:%02d:%02d", hours, minutes, seconds); 
  // outputs: 03:18:23
}
DannyMo
  • 11,344
  • 4
  • 31
  • 37
0

Problems:

  • You are cramming a time-of-day value into a date-time object.
  • You are using notoriously troublesome old date-time classes, now legacy, supplanted by the java.time classes.

The LocalTime class represents a time-of-day value without a date and without a time zone.

LocalTime start = LocalTime.parse( "00:44:16" ); 
LocalTime stop = LocalTime.parse( "04:02:39" );

The Duration represents a span of time not attached to the timeline.

Duration duration = Duration.between ( start , stop );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154