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

2018-12-31 14:12发布

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.

15条回答
旧人旧事旧时光
2楼-- · 2018-12-31 15:05

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.

查看更多
像晚风撩人
3楼-- · 2018-12-31 15:07

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("")
查看更多
余欢
4楼-- · 2018-12-31 15:10

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();

}
查看更多
宁负流年不负卿
5楼-- · 2018-12-31 15:12

This is going to be one of the new features in java 7

JSR-310

查看更多
其实,你不懂
6楼-- · 2018-12-31 15:13
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();
}
查看更多
看风景的人
7楼-- · 2018-12-31 15:15

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.

查看更多
登录 后发表回答