Question

Je voudrais formater une durée en secondes en utilisant un motif tel que H: MM: SS. Les utilitaires actuels de Java sont conçus pour formater une heure mais pas une durée.

Était-ce utile?

La solution

Si vous utilisez une version de Java antérieure à la version 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 Durée - vous pouvez alors appeler . toPeriod (en spécifiant le PeriodType que vous voulez indiquer si 25 heures deviennent 1 jour et 1 heure ou non, etc.) pour obtenir un Période que vous pouvez formater.

Si vous utilisez Java 8 ou une version ultérieure: je suggérerais normalement 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, selon la réponse de bobince si vous en avez besoin - même si vous devez faire attention à la situation où la durée est négative, car vouloir probablement un simple signe négatif dans 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 ennuyant. Pour l'analyse , 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.

Autres conseils

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

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

J'utilise les versions communes d'Apache DurationFormatUtils comme suit:

DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
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())));

Cela sera plus facile avec Java 9. Un Durée 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 rend la tâche un peu plus simple:

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

C’est peut-être un peu un hacky, 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();

}

Cela va être l’une des nouvelles fonctionnalités de java 7

JSR-310

Voici encore un exemple pour formater la durée. Notez que cet exemple montre à la fois une durée positive et une durée positive.

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

C’est une option qui fonctionne.

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

Que diriez-vous de la fonction suivante, qui retourne soit + H: MM: SS ou + 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 );
    }
}
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();
}

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,");
}

Il existe une approche assez simple et élégante (OMI), du moins pour des durées inférieures à 24 heures:

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

Les formats ont besoin d’un objet temporel pour pouvoir être formatés. Vous pouvez donc en créer un en ajoutant la durée à une heure locale de 00:00 (c’est-à-dire minuit). Cela vous donnera un LocalTime représentant la durée de minuit à cette heure, qui est ensuite facile à formater en notation standard HH: mm: ss. Cela présente l'avantage de ne pas nécessiter de bibliothèque externe et d'utiliser la bibliothèque java.time pour effectuer le calcul, plutôt que de calculer manuellement les heures, les minutes et les secondes.

Ma bibliothèque Time4J offre une solution basée sur un modèle (similaire à Apache DurationFormatUtils . code>, mais plus souple):

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 capacités de traitement du débordement d’heures et de la gestion des signatures. Voir également l’API de duration-formatter en fonction du modèle .

Dans Scala, construire sur la solution de YourBestBet mais en simplifiant:

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

en scala, aucune 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("")

Je n'ai pas vu celui-ci, alors je pensais l'ajouter:

Date started=new Date();
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
task
long duration=new Date().getTime()-started.getTime();
System.out.println(format.format(new Date(duration));

Cela ne fonctionne que pendant 24 heures, mais c’est ce que je veux habituellement pour une durée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top