0

I'm trying to convert 5007 to HH:mm:ss:SSS, I'm using Netbeans IDE v8.2:

Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
String dateFormatted = formatter.format(date);

But this gives me an incorrect result:

01:00:05:007
^^-------------------------why does it print to me 01 in the hours?

But it should get:

00:00:05:007
^^-------------------------correct result

Netbeans IDE

When I use ideone for example it gives me a correct result:

ideone

Any explication about this problem?

I testes with both versions: Java 7 and Java 8.

Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
  • 5007 milliseconds after 1 jan 1970? – ΦXocę 웃 Пepeúpa ツ Jun 13 '17 at 09:30
  • 1
    My guess is that it has something to do with daylight saving time. Time 0 is probably 1970-01-01 01:00:00:000 – Ted Cassirer Jun 13 '17 at 09:31
  • what did you mean @ΦXocę웃Пepeúpaツ ? – Youcef LAIDANI Jun 13 '17 at 09:31
  • @TedCassirer why it cork fine in ideone? – Youcef LAIDANI Jun 13 '17 at 09:32
  • 1
    Different jdk maybe? Probably just doesn't consider the daylight saving time when you map the amount of ms from epoch to date. I do not know the details so I didn't post it as an answer. – Ted Cassirer Jun 13 '17 at 09:34
  • 1
    @TedCassirer No, not a different JDK, but rather a different default timezone. So I guess you're on the right track. – Tom Jun 13 '17 at 09:36
  • 1
    Ideone uses GMT as their default timezone: http://ideone.com/9qxi16 and OP has CET with is UTC + 1 (currently). – Tom Jun 13 '17 at 09:43
  • thank you @Tom yes when i use GMT it work :) – Youcef LAIDANI Jun 13 '17 at 09:44
  • 1
    Wonder how many times this question has been asked before. Please help yourself to an answer fast by seraching. – Ole V.V. Jun 13 '17 at 10:02
  • 1
    Possible duplicate of [How to convert milliseconds to "hh:mm:ss" format?](https://stackoverflow.com/questions/9027317/how-to-convert-milliseconds-to-hhmmss-format) – Ole V.V. Jun 13 '17 at 10:02
  • @OleV.V. sorry but i think you don't understand the question it is different of that you already mention, it is not how to convert but why it show me incorrect result – Youcef LAIDANI Jun 13 '17 at 10:05
  • Alright, I’ve retracted the close vote because of the duplicate. I still think that you should have searched before asking and if you still needed to ask, have told us what you had found and in what way it didn’t solve your problem. As a rule you’ll get better guidance that way. – Ole V.V. Jun 13 '17 at 10:34
  • 1
    Please, the 5007 in the question, are they a point in time as milliseconds since the epoch or are they a duration measured in milliseconds? – Ole V.V. Jun 13 '17 at 11:00
  • 1
    they are `a duration measured in milliseconds` @OleV.V. – Youcef LAIDANI Jun 13 '17 at 11:03

3 Answers3

4

When you ask for the explanation of your problem I will be honest with you: You are misusing SimpleDateFormat for formatting a duration. It was never meant for this use and is not designed to give you the expected result if you try it anyway. The problem you got is not the only problem you will have. If your duration grows to more than 24 hours, the whole days will not be formatted, so your result will be wrong in a different way.

Apart from that, these days I recommend not using the SimpleDateFormat class at all. Its replacement is java.time.format.DateTimeFormatter, it came out in 2014 and comes with quite fewer negative surprises. It is not a good choice for formatting a duration either, though.

So what is a good choice? I will give you the Java 9 answer first because it is easy:

        Duration dur = Duration.ofMillis(5007);
        String hmss = String.format("%02d:%02d:%02d:%03d", 
                                    dur.toHours(),
                                    dur.toMinutesPart(), 
                                    dur.toSecondsPart(), 
                                    dur.toMillisPart​());

The main advantage isn’t even the ease, it’s the clarity. For example, with this code no one needs to ask the question I asked in a comment, is it a point it time or a duration? The code very clearly states that it is a duration.

For Java 6, 7 and 8, you may still use the Duration class (in Java 6 and 7 through the ThreeTen Backport), but it doesn’t lend itself that easily to formatting, so I think I would resort to using the TimeUnit enum as in the question I had linked to (the link you asked me to remove again):

    long millis = 5007;
    long hours = TimeUnit.MILLISECONDS.toHours(millis);
    millis -= TimeUnit.HOURS.toMillis(hours);
    long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
    millis -= TimeUnit.MINUTES.toMillis(minutes);
    long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
    millis -= TimeUnit.SECONDS.toMillis(seconds);
    String hmss = String.format("%02d:%02d:%02d:%03d", hours, minutes, seconds, millis);

The result is the desired

00:00:05:007

To illustrate the point I was trying to make about what happens when the duration is more than 24 hours, let’s try to give it 100 000 000 milliseconds (there are 86 400 000 millis in a day):

27:46:40:000
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
3
Date date = new Date(5007);

creates a Date which is 5007 milliseconds after January 1, 1970, 00:00:00 GMT.

When you format it with SimpleDateFormat, it is converted to your machine's timezone (which I'm assuming is GMT+1).

When I run your code I get

02:00:05:007

And my timezone is GMT+2.

If you set the timezone of the DateFormat instance to GMT, you'll get the expected output:

Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
formatter.setTimeZone (TimeZone.getTimeZone ("GMT"));
String dateFormatted = formatter.format(date);
System.out.println (dateFormatted);

This prints

00:00:05:007
Eran
  • 387,369
  • 54
  • 702
  • 768
  • thank you @Eran, so what do you suggest to convert millisecond to `HH:mm:ss:SSS` format or i should to make some thing like this https://stackoverflow.com/a/16520928/5558072 ? – Youcef LAIDANI Jun 13 '17 at 09:40
  • setting the timezone to GMT should work. http://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html#setTimeZone(java.util.TimeZone) – Davide Spataro Jun 13 '17 at 09:41
  • yes it work now @DavideSpataro, thank you i appreciate it – Youcef LAIDANI Jun 13 '17 at 09:43
  • @YCF_L Do you want the `date` variable to actually contain the `Date` represented by the milliseconds offset, but in your own local timezone, or do you just want to get it printed as `HH:mm:ss:SSS`? If it's the latter, just add `formatter.setTimeZone (TimeZone.getTimeZone ("GMT"));` as shown in my answer. – Eran Jun 13 '17 at 09:44
1

It is definitely a Locale issue. When you do not specify one it will use the (your system) default one. To override this;

try either adding this

formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

or passing a Locale when constructing the SimpleDateFormat instance. For example:

DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS", Locale.ENGLISH); 

I assume Locale.ENGLISH has UTC timezone btw, but I hope you get the idea.

ipper
  • 624
  • 4
  • 13
  • It’s a good idea to provide an explicit locale, it makes your intentions clearer to the reader. It hardly makes any difference on the output in this case, though. – Ole V.V. Jun 13 '17 at 11:47