How to Format a Duration in Java (E.G Format H:Mm:Ss)

How to format a duration in java? (e.g format H:MM:SS)

If you're using a version of Java prior to 8... you can use Joda Time and PeriodFormatter. If you've really got a duration (i.e. an elapsed amount of time, with no reference to a calendar system) then you should probably be using Duration for the most part - you can then call toPeriod (specifying whatever PeriodType you want to reflect whether 25 hours becomes 1 day and 1 hour or not, etc) to get a Period which you can format.

If you're using Java 8 or later: I'd normally suggest using java.time.Duration to represent the duration. You can then call getSeconds() or the like to obtain an integer for standard string formatting as per bobince's answer if you need to - although you should be careful of the situation where the duration is negative, as you probably want a single negative sign in the output string. So something like:

public static String formatDuration(Duration duration) {
long seconds = duration.getSeconds();
long absSeconds = Math.abs(seconds);
String positive = String.format(
"%d:%02d:%02d",
absSeconds / 3600,
(absSeconds % 3600) / 60,
absSeconds % 60);
return seconds < 0 ? "-" + positive : positive;
}

Formatting this way is reasonably simple, if annoyingly manual. For parsing it becomes a harder matter in general... You could still use Joda Time even with Java 8 if you want to, of course.

How can I pretty print a Duration in Java?

Joda Time has a pretty good way to do this using a PeriodFormatterBuilder.

Quick Win: PeriodFormat.getDefault().print(duration.toPeriod());

e.g.

//import org.joda.time.format.PeriodFormatter;
//import org.joda.time.format.PeriodFormatterBuilder;
//import org.joda.time.Duration;

Duration duration = new Duration(123456); // in milliseconds
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendDays()
.appendSuffix("d")
.appendHours()
.appendSuffix("h")
.appendMinutes()
.appendSuffix("m")
.appendSeconds()
.appendSuffix("s")
.toFormatter();
String formatted = formatter.print(duration.toPeriod());
System.out.println(formatted);

Formatting a Duration in Java 8 / jsr310

There is no period/duration-formatter in jsr-310, different from JodaTime. Not every feature of JodaTime was ported to JSR-310 (for example also not PeriodType). And in reverse JSR-310 has some features which are not available in JodaTime (for example localized weekday numbers or the strategy pattern approach with adjusters).

It might happen that Java 9 will introduce some kind of built-in period formatting (read something about this from S. Colebourne).

Conclusion: JSR-310 and JodaTime are not fully compatible to each other, so a lot of work can be required. I would not be so keen on migration as soon as possible. Do you need special features of JSR-310 which are not offered by JodaTime?

Additional note: You should also be aware of the fact that joda period (which includes all units from years to seconds) is not fully compatible with jsr310-period (only years, months, days) or jsr310-duration (only hours, minutes, seconds and fraction seconds).

SimpleDateFormat mm:ss format - minutes get padded with a 3

It’s a time zone problem. Or more precisely, a problem of misusing SimpleDateFormat for something that it wasn’t meant for. Here’s a way you can reproduce:

    TimeZone.setDefault(TimeZone.getTimeZone("America/St_Johns"));
SimpleDateFormat timeFormatter = new SimpleDateFormat("mm:ss", Locale.getDefault());
System.out.println(timeFormatter.format(new Date(5*60*1000)));

Output from this snippet is:

35:00

Explanation:
new Date(5*60*1000) produces a date-time of 5 minutes after the epoch, that is 00:05:00 UTC on January 1, 1970. At this time as at any other time, different zones of the world have different times. However, most time zones have an offset from UTC of a whole number of hours. So the time will be 5 minutes past the hour, and your formatter will print it as 05:00. This is why you didn’t notice the problem before. For example, in Berlin it will be 01:05:00, and in New York it will be 19:05:00 the evening before. However, there are also time zones that have offsets from UTC that are not a whole number of hours. For example Asia/Kolkata is at +05:30 and Asia/Kathmandu is at +05:45. In such a time zone, the time will not be 5 minutes past the hour, and you will get an unexpected result like the one you saw.

Suggested solutions include:

  • Use TimeUnit for converting seconds into minutes and seconds and String.format for formatting them into two digits each.
  • If you want a nice solution and you’re OK with an external dependency on an old library in maintenance mode, look into the PeriodFormatter of Joda-Time.

Here’s an example of using TimeUnit for calculating the parts to format as suggested in the first bullet:

    long totalSeconds = TimeUnit.MINUTES.toSeconds(5); // 300

long minutes = TimeUnit.SECONDS.toMinutes(totalSeconds);
long secondsPart = totalSeconds - TimeUnit.MINUTES.toSeconds(minutes);
String formattedDuration = String.format("%02d:%02d", minutes, secondsPart);
System.out.println("Formatted duration: " + formattedDuration);

Output:

Formatted duration: 05:00

The ugly hack that I wouldn’t suggest would be to set the time zone of your formatter to UTC.

There’s a lot more inspiration in the question I already linked to in a comment. At time of writing it has 20 answers. I am repeating the link at the bottom.

And by the way, even for formatting and parsing dates and times, you may consider not using SimpleDateFormat. It’s notoriously troublesome and long outmoded. Instead add ThreeTenABP to your Android project in order to use java.time, the modern Java date and time API. It is so much nicer to work with.

Links

  • Joda-Time home page.
  • Stack Overflow question: How to format a duration in java? (e.g format H:MM:SS).
  • Oracle tutorial: Date Time explaining how to use java.time.
  • Java Specification Request (JSR) 310, where java.time was first described.
  • ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
  • ThreeTenABP, Android edition of ThreeTen Backport
  • Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

I want to be able to use a long value into a hh:mm:ss format from another class in a method in Java

java.time.Duration

java.time is almost always where you want to go when you have time/date stuff to do.

java.time.Duration d = Duration.ofMillis((long) (1000L * sum));

then you can format that with a DateTimeFormatter from the j.t.format package as you want.

How do i format a java.time.Duration mm:ss

You could create a LocalTime representing the duration from midnight (00:00) and use a DateTimeFormatter:

LocalTime t = LocalTime.MIDNIGHT.plus(duration);
String s = DateTimeFormatter.ofPattern("m:ss").format(t);

Note that this will only work for durations less than one hour.

Compare two time in MM:SS format

As LocalTime seems to be unable to use a DateTimeFormatter pattern of mm:ss, you can also make a short static helper method that is called instead.

This method sets a default hour for all parses to the same value, which does not expose the "00:" anywhere else which could be bug prone if a different hour is accidentally entered.

This will ensure any Duration.between() for minutes and seconds will be accurate:

public static void main(String [] args) {
LocalTime start = parseHelper("20:28");
LocalTime stop = parseHelper("20:18");
Duration duration = Duration.between(start, stop);
System.out.println(duration.getSeconds());
}

private static LocalTime parseHelper(String str) {
return LocalTime.parse("00:" + str);
}

Output:

-10

EDIT:

Here are some docs that reinforce that hours are not optional in LocalTime, and apparently neither are minutes.

Here you can see they list the possible values in the toString() method.

The output will be one of the following ISO-8601 formats:

HH:mm
HH:mm:ss
HH:mm:ss.SSS
HH:mm:ss.SSSSSS
HH:mm:ss.SSSSSSSS


Related Topics



Leave a reply



Submit