pilcrowpipe
pilcrowpipe

Reputation: 2658

Zero-pad hour in DateFormat

I am trying to display a time difference into a string which follows the form 00:00:00 (hours:minutes:seconds), zero-padded. I have the following code:

long timeDiff = System.currentTimeMillis() - mStartRecordingTime;
time = DateFormat.format("hh:mm:ss", timeDiff).toString(); 

I was testing it when the timeDiff was no more than a few seconds but the hour does not show as 00. I am in the JST timezone by the way.

Upvotes: 2

Views: 5570

Answers (4)

Basil Bourque
Basil Bourque

Reputation: 339472

tl;dr

Duration.between( 
    LocalTime.of( 12 , 5 , 0 ) ,
    LocalTime.of( 12 , 7 , 0 ) 
).toString()

PT2M

If, against my strong recommendation to use Duration, you insist on using ambiguous/confusing time-of-day formatting:

LocalTime.MIN.plus(
    Duration.between( 
        LocalTime.of( 12 , 5 , 0 ) ,
        LocalTime.of( 12 , 7 , 0 ) 
    )
).toString();

00:02

To force all three components (hours, minutes, seconds), use the predefined DateTimeFormatter.ISO_LOCAL_TIME.

LocalTime.MIN.plus(
    Duration.between( 
        LocalTime.of( 12 , 5 , 0 ) ,
        LocalTime.of( 12 , 7 , 0 ) 
    )
).format( DateTimeFormatter.ISO_LOCAL_TIME )

00:02:00

See live code in IdeOne.com.

Moment != span-of-time

Do not abuse a date-time class such as java.util.Date to store elapsed time. Such a class represents a moment, not a span of time.

Avoid legacy date-time classes

Do not use troublesome old date-time classes such as java.util.Date. Those are now supplanted by java.time classes.

Instant

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.

Get the current moment.

Instant now = Instant.now();

Simulate a later time.

Instant future = now.plus( Duration.ofMinutes( 5 ) );

Duration

Capture elapsed time with a Duration or Period object. Each of these represent a span of time, the first handles days-hours-minutes-seconds and the second handles years-months-days.

Duration duration = Duration.between( now , future );

String format

To present that duration value as a String, do not use time-of-day formatting as that is ambiguous. Instead use standard ISO 8601 format for durations. This format, PnYnMnDTnHnMnS, marks the beginning with a P. The T in the middle separates the years-months-days portion from the hours-minutes-seconds portion. For example, two and a half hours is PT2H30M. Our example here of five minutes is PT5M.

String output = duration.toString();  // PT5M

LocalTime

If you do have an actual time-of-day and want to format with padding zeros, use the default format of LocalTime::toString.

LocalTime.now( ZoneId.of( "America/Montreal" ) ).toString();  // 02:03:04.789Z

Another example. Again, I do not recommend abusing LocalTime this way. (Instead, stick with Duration for elapsed time.)

LocalTime start = LocalTime.now( ZoneId.of( "America/Montreal" ) );
LocalTime stop = start.plusMinutes( 7 );
Duration d = Duration.between( start , stop );
LocalTime result = LocalTime.MIN.plus( d );  // I do *not* recommend abusing `LocalTime` this way. Use `Duration` instead for elapsed time.
DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_TIME ;
String output = result.format( f );
System.out.println( "output: " + output );

output: 00:07:00

See live code in IdeOne.com.


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.

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: 0

arcy
arcy

Reputation: 13133

Where did you get mStartRecordingTime? It doesn't look to me like it was set with System.currentTimeMillis() in the same locale; if it had been, then the time difference would have reflected the actual difference and this would have worked. It appears that the recording time somehow got set with UTC, 9 hours away from JST.

The other poster is correct, a date produced with this value would be near epoch, but if you're just trying to get hours, minutes, and seconds, then you should be all right. Keep in mind that you're dealing with elapsed time, not clock/calendar time, so I wouldn't expect the date formatting (as opposed to time formatting) things to work for you.

Upvotes: 2

Brent Worden
Brent Worden

Reputation: 10994

You need to compensate for the time zone. With what you have, it is probably easiest to change the date formatter to use UTC as the time zone. Here is some code that should help:

    long timeDiff = System.currentTimeMillis() - mStartRecordingTime;
    DateFormat df = new SimpleDateFormat("HH:mm:ss");
    df.setTimeZone(TimeZone.getTimeZone("UTC"));
    String time = df.format(new Date(timeDiff));

Note the change to 'HH' is the date format to display times in a 24 hour format.

Upvotes: 0

Eng.Fouad
Eng.Fouad

Reputation: 117647

Use SimpleDateFormat:

long timeDiff = System.currentTimeMillis() - mStartRecordingTime;
String time = new SimpleDateFormat("hh:mm:ss").format(new Date(timeDiff)); 

Upvotes: 2

Related Questions