Qiushi Li
Qiushi Li

Reputation: 1

Confusions about Java's Date class and getTime() function

I am new to Java's Date class. When I try to use its getTime() function for calculating time difference, issues come out. For example, below is the code.


            Date date = new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

            task = opt.get();
            task.setEndDate(dateFormat.format(date));

            Date startDate = null;
            try {
                startDate = dateFormat.parse(task.getStartDate());
            } catch (ParseException e) {
                System.out.println("date parsing error...");
                startDate = date;
            }

            System.out.printf("Start date is: %s", task.getStartDate());
            System.out.printf("Start date is: %d", startDate.getTime());
            System.out.printf("End date is: %s", task.getEndDate());
            System.out.printf("End date is: %d", date.getTime());

            long diff = date.getTime() - startDate.getTime() - 43200000;
            System.out.printf("Time difference is: %d", diff);
            int secNum = (int)(diff / 1000);

            String timeCost = String.valueOf(secNum);
            System.out.println("Time cost(sec) is:");
            System.out.println(timeCost);
            task.setTimeCost(timeCost);

The outputs are:

Start date is: 2020-04-15 01:46:17
Start date is: 1586929577000
End date is: 2020-04-15 01:46:35
End date is: 1586972795461
Time difference is: 18461
Time cost(sec) is:18

As you might notice, there is 12 hours(43200000 ms) offset between the calculated difference and the real difference through "date.getTime() - startDate.getTime()".

I don't know what's going on. Does anyone have an idea and correct me ?

Upvotes: 0

Views: 701

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 339043

java.time

I am new to Java's Date class.

Stop! Backup, rewind.

Both java.util.Date and java.sql.Date classes are terrible, deeply flawed, and quite frustrating. Never use these classes.

These classes were shipped in the earliest versions of Java. Supplanted years ago by the modern java.time classes defined in JSR 310.


Date date = new Date();

To capture the current moment in UTC, use Instant.now. Uses a resolution finer than the milliseconds used in the java.util.Date class it replaced.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

task.setEndDate(dateFormat.format(date));

Your Task class should hold a java.time object rather than a mere string.

class Task {
    Instant start , stop ;
    …
}

Use smart objects rather than dumb strings throughout your Java codebase. Doing so ensures valid values, provides type-safety, and makes your code more self-documenting.

If your Task is like booking appointments in the future, where you want a certain time-of-day regardless of changes to the offset used by your time zone, then use LocalDateTime. This type represents only a date and time-of-day but lacks any concept of time zone or offset.

LocalDate ld = LocalDate.of( 2020 , Month.APRIL , 15 ) ;
Localtime lt = LocalTime.of( 15 , 30 ) ;
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;

When generating a calendar where you need a specific point on the timeline, then apply the relevant time zone.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

The issue at stake here is the fact that politicians around the world have shown a predilection for changing the offset used by the time zone(s) of their jurisdiction. The politicians do so with surprising frequency. And they have done so with little or no forewarning.

When exchanging date-time values with other systems textually, then use ISO 8601 formats. These formats are used by default in java.time when parsing/generating text. And for presentation to users, produce automatically localized strings using DateTimeFormatter.


new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")

This format is incorrect if you are trying to record moments, specific points on the timeline. You must include an indication of time zone and/or offset-from-UTC to track a moment.

For moments, use the ISO 8601 formats mentioned above. Used by default, so no need to specify a formatting pattern.

String input = "2020-01-23T01:23:45.123456789Z" ;
Instant instant = Instant.parse( input ) ;

Adjust from UTC into the wall-clock time used by the people of a particular region (a time zone).

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Generate localized text.

Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( f ) ;

See this code run live at IdeOne.com.

zdt.toString(): 2020-01-22T20:23:45.123456789-05:00[America/Montreal]

output: mercredi 22 janvier 2020 à 20 h 23 min 45 s heure normale de l’Est


long diff = date.getTime() - startDate.getTime() - 43200000;

No need to do the math yourself. We have a class for that: Duration.

Duration d = Duration.between( start , stop ) ;

If you want a count of whole seconds across the entire span of time, call Duration::toSeconds.

long seconds = d.toSeconds() ;  // Entire duration in terms of whole seconds.

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. Hibernate 5 & JPA 2.2 support java.time.

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

Stepan Kolesnik
Stepan Kolesnik

Reputation: 861

You are using hh which is a 12-hour hour format, hence 20:00 becomes 08:00. You should use HH which is a 24-hour format. The below illustrates the difference.

        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        Date date = new Date(1586973600000L);
        System.out.println(date);

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String fd1 = df.format(date);
        System.out.println(fd1);
        System.out.println(df.parse(fd1));

        df.applyPattern("yyyy-MM-dd HH:mm:ss");
        String fd2 = df.format(date);
        System.out.println(fd2);
        System.out.println(df.parse(fd2));

Also, java.util.Date is old, buggy and generally avoided for some time now. You might want to switch to java.time instead.

Upvotes: 2

Dave Costa
Dave Costa

Reputation: 48121

It seems you are storing the date/time as a string in your task object, and converting between Date and String using the format "yyyy-MM-dd hh:mm:ss". I believe lower-case h means you are using a 12-hour clock, but you do not include an AM/PM indicator in your format string.

I'm guessing you ran the code at 1:46 PM to produce the sample output.

You have "2020-04-15 01:46:17" stored as your start date. When you convert that back to a date, the formatter doesn't know whether it is an AM time or PM time. I guess that it defaults to AM.

The Date object, however, knows that it was initialized with a PM time. Therefore, when you subtract the two, you get over 12 hours difference, because it is subtracting 1:46:17 AM from 1:46:35 PM.

A simple recommendation would be to add an AM/PM indicator to your date format, or use a 24-hour clock (upper-case H in the format string).

An even better recommendation would be to store dates as dates, not as strings! Convert them to strings when you want to display them.

Upvotes: 3

Related Questions