web-dev-qa-db-fra.com

Comment formater une durée en java? (par exemple, format H: MM: SS)

Je voudrais formater une durée en secondes en utilisant un modèle comme H: MM: SS. Les utilitaires actuels en Java sont conçus pour formater une heure mais pas une durée.

126
kofte

Si vous utilisez une version de Java antérieure à 8 ... vous pouvez utiliser Joda Time et PeriodFormatter . Si vous avez vraiment une durée (c.-à-d. Une durée écoulée, sans référence à un système de calendrier), vous devriez probablement utiliser Duration pour la plupart - vous pouvez alors appeler toPeriod (en spécifiant le paramètre PeriodType que vous souhaitez indiquer si 25 heures deviennent 1 jour et 1 heure ou non, etc.) pour obtenir un Period que vous pouvez formater.

Si vous utilisez Java 8 ou une version ultérieure: normalement, je suggérerais d'utiliser Java.time.Duration pour représenter la durée. Vous pouvez ensuite appeler getSeconds() ou similaire pour obtenir un entier pour le formatage de chaîne standard, conformément à la réponse de bobince si nécessaire - même si vous devez faire attention à la situation dans laquelle la durée est négative, car vous souhaitez probablement un single négatif connectez-vous à la chaîne de sortie. Donc, quelque chose comme:

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;
}

Le formatage de cette manière est raisonnablement simple, si manuellement fastidieux. Pour parsing, cela devient en général plus difficile ... Vous pouvez toujours utiliser Joda Time, même avec Java 8, si vous le souhaitez, bien sûr.

69
Jon Skeet

Si vous ne voulez pas glisser dans les bibliothèques, il est assez simple d'utiliser un formateur ou un raccourci associé, par exemple. nombre entier de secondes donné s:

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

J'utilise DurationFormatUtils commun d'Apache like so: 

DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
72
Gili Nachum
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())));
24
Mihai Vasilache

Ce sera plus facile avec Java 9. Une Duration n’est toujours pas formatable (ce que je sais), mais des méthodes permettant d’obtenir les heures, les minutes et les secondes sont ajoutées, ce qui simplifie un peu la tâche:

        Duration diff = // ...;
        String hms = String.format("%d:%02d:%02d", 
                                   diff.toHoursPart(),
                                   diff.toMinutesPart(), 
                                   diff.toSecondsPart());
16
Ole V.V.

C'est peut-être un peu compliqué, mais c'est une bonne solution si vous voulez accomplir cela en utilisant le Java.time de Java 8:

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

}
7
patrick

Cela va être l'une des nouvelles fonctionnalités de Java 7

JSR-310

6
luke

Voici un autre exemple de mise en forme de la durée ..__ Notez que cet exemple montre à la fois la durée positive et la durée négative.

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());
    }
}
6
Pavel_H

Ceci est une option de travail.

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;
}

Appelez la méthode avec

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

Produit quelque chose comme:

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

Que diriez-vous de la fonction suivante, qui renvoie soit + H: MM: SS

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 );
    }
}
2
mksteve
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();
}
1
Bax

Cette réponse utilise uniquement les méthodes Duration et fonctionne avec 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,");
}
1
lauhub

Ma bibliothèque Time4J offre une solution basée sur un modèle (similaire à Apache DurationFormatUtils, mais plus 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

Ce code illustre les fonctionnalités permettant de gérer le débordement d'heures et la gestion des signatures. Voir également l'API de duration-formatter basée sur le modèle .

0
Meno Hochschild

en scala, pas de bibliothèque nécessaire:

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("")
0
YourBestBet

Dans Scala, construire sur la solution de YourBestBet mais simplifié:

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