4

I have very simple code which calculates difference between two times:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;

public class JavaApplication8 {
    private static final SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm:ss.SSS");

    public static void main(String[] args) throws InterruptedException {
        Date start = GregorianCalendar.getInstance().getTime();
        Thread.sleep(100);
        Date end   = GregorianCalendar.getInstance().getTime();

        long diff = end.getTime() - start.getTime();
        System.out.println(timeFormat.format(diff));
    }
}

but it prints 01:00:00.100 instead of 00:00:00.100, why?

tobi
  • 1,944
  • 6
  • 29
  • 48
  • 4
    Basically because SimpleDateFormat is designed to format a date, time or date/time combination, while you are trying to use it to format a period or duration. – jarnbjo Aug 07 '13 at 14:35
  • possible duplicate of [Time difference in Java](http://stackoverflow.com/questions/16948799/time-difference-in-java) – jarnbjo Aug 07 '13 at 14:37
  • @jarnbjo. The duplicate you linked simply converts the duration into a Calendar instance. So, if I convert the duration into Date using `new Date(long)`, then that would be correct according to that post. But, creating a new Date is equivalent to using `long` milliseconds. Any comment on this? – Rohit Jain Aug 07 '13 at 15:24

4 Answers4

5

Other way to solve this. Actually time diff that you having is not millisecs of current time. Its is just time diff, so make a simple division of that u can have hours:mins:secs. And its quite fast.

Date start = GregorianCalendar.getInstance().getTime();
        Thread.sleep(100);
        Date end = GregorianCalendar.getInstance().getTime();

        long longVal = end.getTime() - start.getTime();

        long hours = longVal / 3600000;
        long mins = (longVal % 3600) / 60000;
        long secs = longVal % 60000;

        System.out.println(hours + " " + mins + " " + secs);
Selvaraj
  • 714
  • 2
  • 6
  • 14
4

It's a timezone issue. DateFormat.format() will by default format the date in your default time zone, which seem to be UTC+1.

You should set the timezone for timeFormat to UTC:

timeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(timeFormat.format(diff));

Also, you should use HH instead of hh in your DateFormat. hh is for 12-hour clock.

new SimpleDateFormat("HH:mm:ss.SSS");

Update :

But there is some other major issue. Currently you are trying to format a duration, which you should not do. Java Date API, do not have any concept of period or duration.

The value which you get from formatting is nothing but the number of milliseconds (equivalent to the difference) from epoch. It's returning a Date object, instead. Although the result might seem correct, but technically, the difference between two dates denotes a period or duration, which is not the same as Date (which denotes a particular instant of time).

You should consider moving to Joda Time for this task, which has classes representing these concepts like Period, Instant, and Duration.

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • @RohitJain otherwise why should is say that? – Ran Eldan Aug 07 '13 at 14:42
  • @Disco3. Check the edit. Your format should use `HH`, instead of `hh`. – Rohit Jain Aug 07 '13 at 14:43
  • 1
    @RanEldan. I think you didn't see my edit. Probably you tried with `hh` in the format, which is 12-hour clock. – Rohit Jain Aug 07 '13 at 14:43
  • @RohitJain You right. I tried your answer before you edited it. please edit again so i can remove my down vote. – Ran Eldan Aug 07 '13 at 14:45
  • 1
    Hey, that actually worked. But I wonder whether it's a short-term fix. What if this program is used by people living in another time zone? The program is not intended to be for myself but for people from china, usa etc. – tobi Aug 07 '13 at 14:46
  • Can you please explain how do you edit your answer without it being marked as edited? – m0skit0 Aug 07 '13 at 14:48
  • @m0skit0. Umm. I didn't understand your comment. – Rohit Jain Aug 07 '13 at 14:48
  • @tobi That's not the question you asked here. Don't expect us to extrapolate whatever you want. Your question has been answered. If you want to ask another question, please go ahead... in another question. – m0skit0 Aug 07 '13 at 14:49
  • @RohitJain This was not your first answer (nor the second) but there are no hint you edited it (revisions link). How did you do that? – m0skit0 Aug 07 '13 at 14:50
  • 1
    It is not a timezone issue. The problem is, as I wrote in my comment to the question, that he is trying to use a formatter for one data type to format a second data type. – jarnbjo Aug 07 '13 at 14:50
  • @jarnbjo. Did you try it? And what difference in data type are you talking about? Are you bothered about `long`? – Rohit Jain Aug 07 '13 at 14:51
  • @m0skit0. I agree that was not my first answer. And regarding revision history, I don't know how it happened. – Rohit Jain Aug 07 '13 at 14:52
  • @tobi: This answer does not really solve you problem, it only applies a workaround to correct the first mistake, making the result obviously correct. – jarnbjo Aug 07 '13 at 14:53
  • @Rohit Jain: What part of the difference between timestamp or instant compared to duration or period (as I wrote in my comment) do you not understand? – jarnbjo Aug 07 '13 at 14:56
  • 1
    @jarnbjo Nope. It **IS** a timezone issue. He's not using a second data type. He's using milliseconds which is the data type for DateFormat. 100 milliseconds is a valid datetime, why not? How would you represent that instant of time then? – m0skit0 Aug 07 '13 at 14:57
  • 1
    @m0skit0: He has a number 100, but the meaning of that number is *not* an instant of time, which he could format with SimpleDateFormat. The meaning of the number is a duration or period, for which there are not formatters in the standard Java API. – jarnbjo Aug 07 '13 at 14:58
  • @jarnbjo. I guess, technically it's true that DateFormat does not parse duration. Surprisingly it works, because it takes the difference in milliseconds, to be time from Epoch. Yes this is not the correct way, you're right. But still TimeZone is the issue. – Rohit Jain Aug 07 '13 at 15:00
  • I don't see how time zone can affect an interval of time... Time zone is not the issue. The issue is using a formatter that is made for another data type. – m0skit0 Aug 07 '13 at 15:05
  • 1
    @m0skit0, jarnbo. Updated the answer. Previously it was plain wrong. :( – Rohit Jain Aug 07 '13 at 15:07
  • @m0skit0 I have deleted my answer but it is a time zone issue. `format(long)` is equivalent to `format(new Date(long))` which creates a date based on the epoch. And the time zone difference (the op is in GMT+1) clearly explains the output he is getting. I agree too that a date format is not the appropriate way to format a duration, but the timezone ***is*** the answer to *it prints 01:00:00.100 instead of 00:00:00.100, why?*... – assylias Aug 07 '13 at 15:19
  • @assylias No. The answer is *"You're using a formatter that is not for that type of data"*. The time zone is irrelevant if the formatter is wrong. – m0skit0 Aug 07 '13 at 16:05
4

You have mixed up two concepts:

  • You are measuring a time interval (difference between TWO points in time)
  • You are printing a date (ONE single point in time)

The two are not compatible, you will always get such strange effects. In your case, as pointed out on the other comments, the time zone gets mixed in. The concept of time zones exists only for dates (point in time), but makes no sense for intervals.

You can use the Jodatime library or the JSR 310: Date and Time API (coming with Java 8 I think).

With Jodatime you can explicitely construct a interval:

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

and then format it with a PeriodFormatter

PeriodFormatter daysHoursMinutes = new PeriodFormatterBuilder()
   .appendDays()
   .appendSuffix(" day", " days")
    .appendSeparator(" and ")
    .appendMinutes()
    .appendSuffix(" minute", " minutes")
    .appendSeparator(" and ")
    .appendSeconds()
    .appendSuffix(" second", " seconds")
    .toFormatter();

System.out.println(daysHoursMinutes.print(period));

By separating the concepts of ONE point in time and the time between TWO points in time, you can make sure that there aren't any other surprises (e.g. leap seconds).

stefan.schwetschke
  • 8,862
  • 1
  • 26
  • 30
0

Because your time zone is GMT+1.

If you read the documentation, you'll find what getTime() does:

Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.

So 100 ms means January 1, 1970, 00:00:00.100 GMT, which is January 1, 1970, 01:00:00.100 GMT+1.

You can simply set the time zone you want your time converted to:

timeFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

And you want 24h-style format: HH:mm:ss.SSS, otherwise it will show 12 instead of 00 hours.

EDIT: as jarnbjo said: you're trying to apply a date formatter to an interval of time, which obviously won't work as you expect. There's no such time interval formatters in the Java API. You'll have to write your own.

m0skit0
  • 25,268
  • 11
  • 79
  • 127
  • ... which in turn should not be any problem, as SimpleDateFormat both SimpleDateFormat still uses UnixTimeStamp and as `diff` should be `January 1, 1970, 00:00:00.100` there is nothing wrong. Or do I have an error in my thought? – LuigiEdlCarno Aug 07 '13 at 14:46
  • @LuigiEdlCarno You do have an error. SimpleDateFormat does care about your time zone, and if you don't set it, it will take your system time zone. Yes, that instant of time is universal, but it is not the same hour in different parts of the planet. Now for me it's 16:33 but for someone in China it's 21:33, although our Java timestamp is the exact same number. This is quite difficult to grasp at first, but once you think about it, it's quite easy. – m0skit0 Aug 07 '13 at 14:54
  • Of course, you are right. I had completely ignored that SimpleDateFormat **has** to be timezone specific. – LuigiEdlCarno Aug 07 '13 at 14:57