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

JavaDate FormattingDuration

Java Problem Overview


I'd like to format a duration in seconds using a pattern like H:MM:SS. The current utilities in java are designed to format a time but not a duration.

Java Solutions


Solution 1 - Java

If you don't want to drag in libraries, it's simple enough to do yourself using a Formatter, or related shortcut eg. given integer number of seconds s:

  String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));

Solution 2 - Java

I use Apache common's DurationFormatUtils like so:

DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);

Solution 3 - Java

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.

Solution 4 - Java

This is easier since Java 9. A Duration still isn’t formattable, but methods for getting the hours, minutes and seconds are added, which makes the task somewhat more straightforward:

	LocalDateTime start = LocalDateTime.of(2019, Month.JANUARY, 17, 15, 24, 12);
	LocalDateTime end = LocalDateTime.of(2019, Month.JANUARY, 18, 15, 43, 33);
	Duration diff = Duration.between(start, end);
	String hms = String.format("%d:%02d:%02d", 
								diff.toHours(), 
								diff.toMinutesPart(), 
								diff.toSecondsPart());
	System.out.println(hms);

The output from this snippet is:

> 24:19:21

Solution 5 - Java

long duration = 4 * 60 * 60 * 1000;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
log.info("Duration: " + sdf.format(new Date(duration - TimeZone.getDefault().getRawOffset())));

Solution 6 - Java

There's a fairly simple and (IMO) elegant approach, at least for durations of less than 24 hours:

DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))

Formatters need a temporal object to format, so you can create one by adding the duration to a LocalTime of 00:00 (i.e. midnight). This will give you a LocalTime representing the duration from midnight to that time, which is then easy to format in standard HH:mm:ss notation. This has the advantage of not needing an external library, and uses the java.time library to do the calculation, rather than manually calculating the hours, minutes and seconds.

Solution 7 - Java

This answer only uses Duration methods and works with Java 8 :

public static String format(Duration d) {
	long days = d.toDays();
	d = d.minusDays(days);
	long hours = d.toHours();
	d = d.minusHours(hours);
	long minutes = d.toMinutes();
	d = d.minusMinutes(minutes);
	long seconds = d.getSeconds() ;
	return 
			(days ==  0?"":days+" jours,")+ 
			(hours == 0?"":hours+" heures,")+ 
			(minutes ==  0?"":minutes+" minutes,")+ 
			(seconds == 0?"":seconds+" secondes,");
}

Solution 8 - Java

I'm not sure that is you want, but check this Android helper class

import android.text.format.DateUtils

For example: DateUtils.formatElapsedTime()

[tag:Android] [tag:Date] [tag:Duration] [tag:ElapsedTime]

Solution 9 - Java

This might be kind of hacky, but it is a good solution if one is bent on accomplishing this using Java 8's java.time:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.UnsupportedTemporalTypeException;

public class TemporalDuration implements TemporalAccessor {
    private static final Temporal BASE_TEMPORAL = LocalDateTime.of(0, 1, 1, 0, 0);
    
    private final Duration duration;
    private final Temporal temporal;
    
    public TemporalDuration(Duration duration) {
        this.duration = duration;
        this.temporal = duration.addTo(BASE_TEMPORAL);
    }
    
    @Override
    public boolean isSupported(TemporalField field) {
        if(!temporal.isSupported(field)) return false;
        long value = temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
        return value!=0L;
    }

    @Override
    public long getLong(TemporalField field) {
        if(!isSupported(field)) throw new UnsupportedTemporalTypeException(new StringBuilder().append(field.toString()).toString());
        return temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
    }

    public Duration getDuration() {
        return duration;
    }
    
    @Override
    public String toString() {
        return dtf.format(this);
    }
    
    private static final DateTimeFormatter dtf = new DateTimeFormatterBuilder()
            .optionalStart()//second
            .optionalStart()//minute
            .optionalStart()//hour
            .optionalStart()//day
            .optionalStart()//month
            .optionalStart()//year
            .appendValue(ChronoField.YEAR).appendLiteral(" Years ").optionalEnd()
            .appendValue(ChronoField.MONTH_OF_YEAR).appendLiteral(" Months ").optionalEnd()
            .appendValue(ChronoField.DAY_OF_MONTH).appendLiteral(" Days ").optionalEnd()
            .appendValue(ChronoField.HOUR_OF_DAY).appendLiteral(" Hours ").optionalEnd()
            .appendValue(ChronoField.MINUTE_OF_HOUR).appendLiteral(" Minutes ").optionalEnd()
            .appendValue(ChronoField.SECOND_OF_MINUTE).appendLiteral(" Seconds").optionalEnd()
            .toFormatter();

}

Solution 10 - Java

Here is one more sample how to format duration. Note that this sample shows both positive and negative duration as positive duration.

import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.SECONDS;

import java.time.Duration;

public class DurationSample {
	public static void main(String[] args) {
		//Let's say duration of 2days 3hours 12minutes and 46seconds
		Duration d = Duration.ZERO.plus(2, DAYS).plus(3, HOURS).plus(12, MINUTES).plus(46, SECONDS);
		
		//in case of negative duration
		if(d.isNegative()) d = d.negated();
		
		//format DAYS HOURS MINUTES SECONDS 
		System.out.printf("Total duration is %sdays %shrs %smin %ssec.\n", d.toDays(), d.toHours() % 24, d.toMinutes() % 60, d.getSeconds() % 60);
		
		//or format HOURS MINUTES SECONDS 
		System.out.printf("Or total duration is %shrs %smin %sec.\n", d.toHours(), d.toMinutes() % 60, d.getSeconds() % 60);

		//or format MINUTES SECONDS 
		System.out.printf("Or total duration is %smin %ssec.\n", d.toMinutes(), d.getSeconds() % 60);

		//or format SECONDS only 
		System.out.printf("Or total duration is %ssec.\n", d.getSeconds());
	}
}

Solution 11 - Java

How about the following function, which returns either +H:MM:SS or +H:MM:SS.sss

public static String formatInterval(final long interval, boolean millisecs )
{
    final long hr = TimeUnit.MILLISECONDS.toHours(interval);
    final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
    final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
    final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
    if( millisecs ) {
        return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
    } else {
        return String.format("%02d:%02d:%02d", hr, min, sec );
    }
}

Solution 12 - Java

You can use java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.

Demo:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;

public class Main {
	public static void main(String[] args) {
		LocalDateTime startDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 15, 20, 25);
		LocalDateTime endDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 18, 24, 30);

		Duration duration = Duration.between(startDateTime, endDateTime);
		// Default format
		System.out.println(duration);

		// Custom format
		// ####################################Java-8####################################
		String formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHours() % 24,
				duration.toMinutes() % 60, duration.toSeconds() % 60);
		System.out.println(formattedElapsedTime);
		// ##############################################################################

		// ####################################Java-9####################################
		formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHoursPart(), duration.toMinutesPart(),
				duration.toSecondsPart());
		System.out.println(formattedElapsedTime);
		// ##############################################################################
	}
}

Output:

PT3H4M5S
03:04:05
03:04:05

Learn about the modern date-time API from Trail: Date Time.

Solution 13 - Java

This is a working option.

public static String showDuration(LocalTime otherTime){          
    DateTimeFormatter df = DateTimeFormatter.ISO_LOCAL_TIME;
    LocalTime now = LocalTime.now();
    System.out.println("now: " + now);
    System.out.println("otherTime: " + otherTime);
    System.out.println("otherTime: " + otherTime.format(df));
    
    Duration span = Duration.between(otherTime, now);
    LocalTime fTime = LocalTime.ofNanoOfDay(span.toNanos());
    String output = fTime.format(df);
    
    System.out.println(output);
    return output;
}

Call the method with

System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));

Produces something like:

otherTime: 09:30
otherTime: 09:30:00
11:31:27.463
11:31:27.463

Solution 14 - Java

There is yet another way to make it for java8. But it works if duration is no longer than 24 hours

public String formatDuration(Duration duration) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm.SSS");
    return LocalTime.ofNanoOfDay(duration.toNanos()).format(formatter);
}

Solution 15 - Java

String duration(Temporal from, Temporal to) {
    final StringBuilder builder = new StringBuilder();
    for (ChronoUnit unit : new ChronoUnit[]{YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS}) {
        long amount = unit.between(from, to);
        if (amount == 0) {
            continue;
        }
        builder.append(' ')
                .append(amount)
                .append(' ')
                .append(unit.name().toLowerCase());
        from = from.plus(amount, unit);
    }
    return builder.toString().trim();
}

Solution 16 - Java

using this func

private static String strDuration(long duration) {
	int ms, s, m, h, d;
	double dec;
	double time = duration * 1.0;

	time = (time / 1000.0);
	dec = time % 1;
	time = time - dec;
	ms = (int)(dec * 1000);

	time = (time / 60.0);
	dec = time % 1;
	time = time - dec;
	s = (int)(dec * 60);

	time = (time / 60.0);
	dec = time % 1;
	time = time - dec;
	m = (int)(dec * 60);

	time = (time / 24.0);
	dec = time % 1;
	time = time - dec;
	h = (int)(dec * 24);
	
	d = (int)time;
	
	return (String.format("%d d - %02d:%02d:%02d.%03d", d, h, m, s, ms));
}

Solution 17 - Java

Here's a one-liner for converting a java.time.Duration to a nice string in Kotlin:

duration.run {
   "%d:%02d:%02d.%03d".format(toHours(), toMinutesPart(), toSecondsPart(), toMillisPart())
}

Example output: 120:56:03.004

Solution 18 - Java

My library Time4J offers a pattern-based solution (similar to Apache DurationFormatUtils, but more flexible):

Duration<ClockUnit> duration =
	Duration.of(-573421, ClockUnit.SECONDS) // input in seconds only
	.with(Duration.STD_CLOCK_PERIOD); // performs normalization to h:mm:ss-structure
String fs = Duration.formatter(ClockUnit.class, "+##h:mm:ss").format(duration);
System.out.println(fs); // output => -159:17:01

This code demonstrates the capabilities to handle hour overflow and sign handling, see also the API of duration-formatter based on pattern.

Solution 19 - Java

Looking at all those calculations, it may is helpful that most of the Units (Hours, Minutes, etc.) have a .toFooPart() convenience method.

E.g.

Duration.ofMinutes(110L).toMinutesPart() == 50

Read: the minutes elapsed to the next value of the parent unit (Hour).

Solution 20 - Java

In scala (I saw some other attempts, and wasn't impressed):

def formatDuration(duration: Duration): String = {
  import duration._ // get access to all the members ;)
  f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
}

Looks horrible yes? Well that's why we use IDEs to write this stuff so that the method calls ($toHoursPart etc) are a different color.

The f"..." is a printf/String.format style string interpolator (which is what allows the $ code injection to work) Given an output of 1 14:06:32.583, the f interpolated string would be equivalent to String.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)

Solution 21 - Java

In Scala, building up on YourBestBet's solution but simplified:

def prettyDuration(seconds: Long): List[String] = seconds match {
  case t if t < 60      => List(s"${t} seconds")
  case t if t < 3600    => s"${t / 60} minutes" :: prettyDuration(t % 60)
  case t if t < 3600*24 => s"${t / 3600} hours" :: prettyDuration(t % 3600)
  case t                => s"${t / (3600*24)} days" :: prettyDuration(t % (3600*24))
}

val dur = prettyDuration(12345).mkString(", ") // => 3 hours, 25 minutes, 45 seconds

Solution 22 - Java

in scala, no library needed:

def prettyDuration(str:List[String],seconds:Long):List[String]={
  seconds match {
    case t if t < 60 => str:::List(s"${t} seconds")
    case t if (t >= 60 && t< 3600 ) => List(s"${t / 60} minutes"):::prettyDuration(str, t%60)
    case t if (t >= 3600 && t< 3600*24 ) => List(s"${t / 3600} hours"):::prettyDuration(str, t%3600)
    case t if (t>= 3600*24 ) => List(s"${t / (3600*24)} days"):::prettyDuration(str, t%(3600*24))
  }
}
val dur = prettyDuration(List.empty[String], 12345).mkString("")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkofteView Question on Stackoverflow
Solution 1 - JavabobinceView Answer on Stackoverflow
Solution 2 - JavaGili NachumView Answer on Stackoverflow
Solution 3 - JavaJon SkeetView Answer on Stackoverflow
Solution 4 - JavaOle V.V.View Answer on Stackoverflow
Solution 5 - JavaMihai VasilacheView Answer on Stackoverflow
Solution 6 - JavactgView Answer on Stackoverflow
Solution 7 - JavalauhubView Answer on Stackoverflow
Solution 8 - JavaSergei MaleevView Answer on Stackoverflow
Solution 9 - JavapatrickView Answer on Stackoverflow
Solution 10 - JavaPavel_HView Answer on Stackoverflow
Solution 11 - JavamksteveView Answer on Stackoverflow
Solution 12 - JavaArvind Kumar AvinashView Answer on Stackoverflow
Solution 13 - JavasbclintView Answer on Stackoverflow
Solution 14 - JavastanleyView Answer on Stackoverflow
Solution 15 - JavaBaxView Answer on Stackoverflow
Solution 16 - JavaipsercView Answer on Stackoverflow
Solution 17 - JavaGraham LeaView Answer on Stackoverflow
Solution 18 - JavaMeno HochschildView Answer on Stackoverflow
Solution 19 - JavasschrassView Answer on Stackoverflow
Solution 20 - JavaStephenView Answer on Stackoverflow
Solution 21 - JavadpoetzschView Answer on Stackoverflow
Solution 22 - JavaYourBestBetView Answer on Stackoverflow