Donato Szilagyi
Donato Szilagyi

Reputation: 4369

SimpleDateFormat fails to format Date interval?

I try to format a time interval using SimpleDateFormat.

import java.text.*;
import java.util.*;

public class DateFormatTest {
  public static void main(String[] args) {
    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
    long interval = 1000;
    System.out.println("Interval in millis: " + interval);
    System.out.println("Expected result: 00:00:01");
    System.out.println("Result using Date and SimpleDateFormat: " +
      sdf.format(new Date(interval)));
  }
}

I get the following result:

Interval in millis: 1000
Expected result: 00:00:01
Result using Date and SimpleDateFormat: 01:00:01

I am in GMT+1 time zone. But it should not be reflected in the result.

Of course it can be solved with System.out.printf, but what I am searching is the reason.

Upvotes: 3

Views: 572

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338795

Wrong data type

You are using the wrong class. You are trying to represent a duration of milliseconds and a time-of-day. Neither fits the Date class. That class represents a moment (a date, with time-of-day, in context of UTC).

Table of all date-time types in Java, both modern and legacy

Also, java.util.Date is a terrible class, designed by people who did not understand date-time handling. Now obsolete.

java.time

The modern solution uses java.time classes.

LocalTime

Specifically, LocalTime for a time-of-day using a generic 24-hour day, without a date, and without the context of a time zone or offset-from-UTC.

The start of a day for generic days is 00:00:00. We have a constant for that: LocalTime.MIN. But know that in various time zones, on various dates, the day may start at another time such as 01:00:00.

LocalTime lt = LocalTime.of( 15 , 30 ) ;  // 3:30 PM.

Duration

To represent a span-of-time unattached to the timeline, on a scale of hours-minutes-seconds, use Duration class.

Duration d = Duration.ofMilliseconds( 1_000 ) ;

We can do math with date-time objects.

LocalTime lt = LocalTime.MIN.plus( d ) ;

You should know that java.time classes use a resolution of nanoseconds, much finer than the milliseconds used by the legacy date-time classes.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500903

I am in GMT+1 time zone. But it should not be reflected in the result.

Then you should set the time zone in the SimpleDateFormat. SimpleDateFormat is doing exactly the right thing - it's formatting the instant in time (just after midnight UTC 1970) in the time zone it's working in.

To change the time zone, just use:

sdf.setTimeZone(TimeZone.getTimeZone("etc/UTC"));

It's not clear whether you should really be using SimpleDateFormat at all, though. You're not trying to format a date/time - you're trying to format an interval, given your variable name.

I suggest you use Joda Time which has a much richer type system, and will allow you to express what you really want.

Also, if you really want to use SimpleDateFormat, you probably want to use HH instead of hh in your format string. (hh is a 12-hour value, 1-12. You want 00:00:01, not 12:00:01.) hh is rarely appropriate when you don't also have an am/pm designator in your pattern.

Upvotes: 3

assylias
assylias

Reputation: 328649

I am in GMT+1 time zone. But should not be reflected in the result.

What makes you think so? new Date(0) is at 00:00AM GMT on Jan 1st 1970. So it is at 01:00AM if your default timezone is GMT + 1.

Upvotes: 4

Related Questions