Java SimpleDateFormat: an hour wrong
Asked Answered
C

3

13

I don't need a whole story to clarify my question, so I'll just show the code (which is a mere example). How come there is a difference in my result?

Code

long millis = 2305293L;
System.out.println(
    millis + "ms = " + 
    (millis / 1000) + "s = " + 
    (millis / 1000 / 60) + "m");
System.out.println(
    new SimpleDateFormat("HH:mm:ss").
    format(
        new Date(millis)
        )
    );

Output

2305293ms = 2305s = 38m
01:38:25
Causality answered 2/1, 2013 at 15:36 Comment(0)
H
41

If you are in London, or Paris, the timezone was GMT+1 on 1 Jan 1970.

For reasons @ARC explains in the comments, the UK used GMT+1 or UTC+1 from 18 Feb 1968 to 31 Oct 1971

is it possible for me to convert a long without any timezones interfering?

Set the TimeZone to be GMT.

long millis = 2305293L;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(sdf.format(new Date(millis)));

prints

00:38:25.293
Hungarian answered 2/1, 2013 at 15:39 Comment(12)
Oh my... so, is it possible for me to convert a long without any timezones interfering?Causality
The stuff I know is so random, it's not even useful for Trivial Pursuit ;)Hungarian
Ah great, thanks for your help Peter. I will accept your answer as soon as Stackoverflow allows me to do so.Causality
If someone want to know why, he can read about, BST (British Summer Time). That period was a failed experiment to bring it back to life.Stereography
Apparently it was an experiment called British Standard Time. Wikipedia: Analysis of accident data for the first two years of the experiment indicated that while there had been an increase in casualties in the morning, there had been a substantially greater decrease in casualties in the evening, with a total of around 2,700 fewer people killed and seriously injured during the first two winters of the experiment, at a time when about 1,000 people a day were killed or seriously injured on the roads.Botzow
@Botzow Sounds like they should have kept it. For me it's dark on the way to work and dark on the way home in winter so GMT+0 or GMT+1 makes no difference to me.Hungarian
Well, I just love how results for experiments can be skewed if you conveniently forget to mention other aspects of the time period. For example, the fact that drunk driving laws were implemented around that time and people (hopefully) only drink in the evenings.Botzow
@Botzow In Australia there is law which determines how close the front windows of houses facing each other can be. It was based on how far someone in England determined you would be able to see someone undressing if there houses were closer (under lighting conditions in England) ;)Hungarian
@Peter Lawrey Further evidence of the absolutely random facts you know.Botzow
@Botzow The earth weighs about the same as 1.4*10^27 sugar cubes. (had to check as it's been a while since I used that info ;)Hungarian
@PeterLawrey You did use that info ?Greyson
@dystroy The last time I claimed to know some useless facts. ;) I read it in a book once.Hungarian
G
2

Try this :

System.out.println(new java.util.Date (0));

you will see it begins at 01:00:00, hence the difference of one hour.

Grandmotherly answered 2/1, 2013 at 15:42 Comment(7)
Yes, I noticed the difference. Hence the question as to what causes it. But Peter already covered it perfectly.Causality
I don't think it's due to London/Paris time zone in 1970-01-01. AFAIK the Date(0) is built like that (with getHours()==1) anywhere in the world, i.e. regardless of the default system timezone. Check https://mcmap.net/q/903094/-simpledateformat-gethours-return-incorrect-value.Phail
It is because of time zone, @PJ_Finnegan. However I recommend we don’t use Date. That class is poorly designed and long outdated. Instead use Instant and other classes from java.time, the modern Java date and time API.Ugaritic
@Ole V.V. I'm not in the London/Paris timezone but I used to get a +1 offset as well on the hours when I created a Date(0)Phail
@Phail Which time zone are you in and what do you get from new Date(0)? When I set my JVM’s default time zone to Asia/Tokyo and try new Date(0), I get Thu Jan 01 09:00:00 JST 1970. With Asia/Kolkata I get Thu Jan 01 05:30:00 IST 1970.Ugaritic
@OleV.V. Europe/Rome, and you can see my results in the link I posted in the original comment.Phail
Thanks, @PJ_Finnegan. Rome too was at GMT offset +01:00 on 1 January 1970, which explains why you get 01:00:00 (if in doubt: on timeanddate.com/time/zone/italy/rome, in the dropdown select 1960 — 1969 and see that the last change in 1969 was when summer time ended on 28 September and offset UTC+1h began).Ugaritic
U
1

The other answers are correct and were good answers when the question was asked in 2013. Today we should no longer use Date nor SimpleDateFormat, so I would like to show you a couple of modern code snippets instead. The correct way to format your (in this case) 2 305 293 milliseconds depends on what they represent. I am presenting three options for three different situations.

Formatting a number of milliseconds since the epoch

You need to decide in which time zone you want to interpret your point in time. For example:

    long millis = 2_305_293L;
    DateTimeFormatter formatter = DateTimeFormatter
            .ofLocalizedDateTime(FormatStyle.LONG)
            .withLocale(Locale.ENGLISH);
    ZonedDateTime dateTime = Instant.ofEpochMilli(millis)
            .atZone(ZoneId.of("America/Coral_Harbour"));
    String formattedTime = dateTime.format(formatter);
    System.out.println(formattedTime);

December 31, 1969 at 7:38:25 PM EST

Since at the epoch Coral Harbor was at UTC offset -05:00, we get a time near the end of 1969. If you want the time in UTC (since the epoch is defined in UTC; in other words, if you want 00:38:25), it’s a bit different:

    DateTimeFormatter formatter = DateTimeFormatter
            .ofLocalizedDateTime(FormatStyle.MEDIUM)
            .withLocale(Locale.ENGLISH);
    OffsetDateTime dateTime = Instant.ofEpochMilli(millis)
            .atOffset(ZoneOffset.UTC);

Jan 1, 1970, 12:38:25 AM

In addition to time zone you may vary the language through the locale and the length of the format through the format style (full, long, medium, short). If you want the time of day without the date, use ofLocalizedTime instead of ofLocalizedDateTime.

Formatting a millisecond of day

Assuming your milliseconds are since 0:00 (“midnight”) in whatever time zone:

    LocalTime time = LocalTime.MIN.with(ChronoField.MILLI_OF_DAY, millis);
    System.out.println(time);

00:38:25.293

If this format is satisfactory, you don’t need any explicit formatter. If not, you may use a DateTimeFormatter.

Formatting a duration, an amount of time

An amount of time is a completely different thing from a time and is handled as a Duration object. There is no direct support for formatting it, but since Java 9 it’s not so hard (when you know how):

    Duration amountOfTime = Duration.ofMillis(millis);
    String formattedTime = String.format("%02d:%02d:%02d",amountOfTime.toHours(),
            amountOfTime.toMinutesPart(), amountOfTime.toSecondsPart());
    System.out.println(formattedTime);

00:38:25

Link

Oracle tutorial: Date Time explaining how to use java.time.

Ugaritic answered 4/6, 2019 at 14:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.