dm56
dm56

Reputation: 23

SimpleDateFormat parse returns wrong value

I have this code:

public static String formatMinSecOrHourMinSec(final String length) {
        try {
            final SimpleDateFormat hhmmss = new SimpleDateFormat("HH:mm:ss", Locale.GERMAN);
            final Date date = hhmmss.parse(length);
            final GregorianCalendar gc0 = new GregorianCalendar(Locale.GERMAN);
            gc0.setTime(date);
            if(gc0.getTimeInMillis() >= 3600 * 1000){
                return hhmmss.format(gc0.getTime());
            }else{
                final SimpleDateFormat mmss = new SimpleDateFormat("mm:ss");
                return mmss.format(gc0.getTime());                    
            }
        } catch (final ParseException e) {
            LOGGER.debug("Konnte die Länge nicht parsen: " + length + "\n" + e);
            return length;
        }
    }

I estimate that it returns 01:29:00 if length is set to 01:29:00 but it returns 29:00. This is because gc0.getTimeInMillis() returns one hour less (3600 * 1000) than expected. What am I doing wrong ?

Upvotes: 2

Views: 1175

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 340108

tl;dr

Do not conflate a span-of-time with a time-of-day. Two different concepts deserve two different classes. A span-of-time is represented by the Duration (or Period) class.

Duration
.ofHours( 1 )
.plusMinutes( 29 ) 

…or…

Duration
.parse( "PT1H29M" ) 

Wrong classes

First, you are using inappropriate classes. Apparently you are trying to track a span-of-time but are using time-of-day to do so. A span and a time are two different concepts. Mixing the two leads to ambiguity, confusion, and errors.

Second, you are using terrible old classes that were supplanted years ago by the java.time classes. Never use SimpleDateFormat, GregorianCalendar, etc.

Span-of-time

The correct class for a span-of-time in the range of hours-minutes-seconds is Duration. For a range of years-months-days, use Period.

You can instantiate your Duration from numbers of hours and minutes.

Duration d = Duration.ofHours( 1 ).plusMinutes( 29 ) ; 

Or you can parse a string in standard ISO 8601 format, PnYnMnDTnHnMnS.

Duration d = Duration.parse( "PT1H29M" ) ;

Date-Time math

You can do math with date-time values. Perhaps you want to know when is an hour and twenty-nine minutes from now.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;  
ZonedDateTime now = ZonedDateTime.now( z ) ; // Capture the current moment as seen though the wall-clock time used by the people of some particular region.
ZonedDateTime later = now.plus( d ) ;  // Add a span-of-time to determine a later moment (or an earlier moment if the `Duration` is negative). 

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.

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

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

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

FazoM
FazoM

Reputation: 4956

this is because java.util.Date is using your default time zone. (print time in ms from date and you will see). To fix it try:

final SimpleDateFormat hhmmss = new SimpleDateFormat("HH:mm:ss");
hhmmss.setTimeZone(TimeZone.getTimeZone("UTC"));

Upvotes: 1

Related Questions