Comment convertir des millisecondes en «X minutes, x secondes» en Java?

573

Je veux enregistrer le temps en utilisant System.currentTimeMillis()quand un utilisateur commence quelque chose dans mon programme. Quand il aura fini, je soustrais le courant System.currentTimeMillis()de la startvariable, et je veux leur montrer le temps écoulé en utilisant un format lisible par l'homme tel que "XX heures, XX minutes, XX secondes" ou même "XX minutes, XX secondes" car son pas susceptible de prendre quelqu'un une heure.

Quelle est la meilleure façon de procéder?

Cliquez Upvote
la source
5
S'ils prennent plus d'une heure, vous pouvez toujours imprimer quelque chose comme; 90 minutes, 53 secondes.
Peter Lawrey
1
ma réponse arrive 6 ans en retard mais je pense qu'elle est plus générique que les acceptées: stackoverflow.com/a/35082080/82609
Sebastien Lorber
1
consultez un exemple simple pour convertir des millisecondes en jours, heures, minutes et secondes en Java
sumit kumar pradhan

Réponses:

1229

Utilisez la java.util.concurrent.TimeUnitclasse:

String.format("%d min, %d sec", 
    TimeUnit.MILLISECONDS.toMinutes(millis),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);

Remarque: TimeUnitfait partie de la spécification Java 1.5, mais a toMinutesété ajoutée à partir de Java 1.6.

Pour ajouter un zéro non significatif pour les valeurs 0-9, faites simplement:

String.format("%02d min, %02d sec", 
    TimeUnit.MILLISECONDS.toMinutes(millis),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);

Si TimeUnitou ne toMinutessont pas pris en charge (comme sur Android avant l'API version 9), utilisez les équations suivantes:

int seconds = (int) (milliseconds / 1000) % 60 ;
int minutes = (int) ((milliseconds / (1000*60)) % 60);
int hours   = (int) ((milliseconds / (1000*60*60)) % 24);
//etc...
siddhadev
la source
5
mois int = (int) ((float) jours / 30.4368499f); années int = (int) ((float) jours / 365.242199f);
Nathan Schwermann
7
Je suggère d'utiliser le mod 60 au lieu de soustraire les minutes, il a l'air plus propre. Cependant, il faut savoir que 1 min = 60 sec pour le faire ... =)
Per Alexandersson
2
@AndreasDietrich SimpleDateFormat ne fonctionne pas pour les différences de temps car il ne renvoie que la date de l'époque!
Muhammad Babar
5
int hours = (int) ((milliseconds / (1000*60*60)) % 24)ça ne marche pas! au lieu de cela, cela devrait être comme çaint hours = (int) (milliseconds / (1000*60*60)) ;
Muhammad Babar
5
Si quelqu'un veut un format pour les fichiers vidéo ( h: mm: ss ):String.format("%01d:%02d:%02d", hours, minutes, seconds);
kazy
124

Sur la base de la réponse de @ siddhadev, j'ai écrit une fonction qui convertit les millisecondes en une chaîne formatée:

   /**
     * Convert a millisecond duration to a string format
     * 
     * @param millis A duration to convert to a string form
     * @return A string of the form "X Days Y Hours Z Minutes A Seconds".
     */
    public static String getDurationBreakdown(long millis) {
        if(millis < 0) {
            throw new IllegalArgumentException("Duration must be greater than zero!");
        }

        long days = TimeUnit.MILLISECONDS.toDays(millis);
        millis -= TimeUnit.DAYS.toMillis(days);
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
        millis -= TimeUnit.HOURS.toMillis(hours);
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
        millis -= TimeUnit.MINUTES.toMillis(minutes);
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);

        StringBuilder sb = new StringBuilder(64);
        sb.append(days);
        sb.append(" Days ");
        sb.append(hours);
        sb.append(" Hours ");
        sb.append(minutes);
        sb.append(" Minutes ");
        sb.append(seconds);
        sb.append(" Seconds");

        return(sb.toString());
    }
Brent écrit le code
la source
2
Vous devriez y faire une recherche de simple / multiple, afin d'éviter ce genre de situation:1 Days 1 Hours 1 Minutes 1 Seconds
Daniel
7
Nous pourrions utiliser la fonction module au lieu de la soustraction: long days = TimeUnit.MILLISECONDS.toDays(millis); long hours = TimeUnit.MILLISECONDS.toHours(millis) % 24; long minutes = TimeUnit.MILLISECONDS.toMinutes(millis) % 60; long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60; long milliseconds = millis % 1000; ainsi que la méthode String.format:return String.format("%d Days %d Hours %d Minutes %d Seconds %d Milliseconds", days, hours, minutes, seconds, milliseconds);
Jose Tepedino
78
long time = 1536259;

return (new SimpleDateFormat("mm:ss:SSS")).format(new Date(time));

Tirages:

25: 36: 259

Damien
la source
1
J'aime l'approche ci-dessus la meilleure si rien d'autre que sa simplicité! Comme nous avons affaire à des durées et des durées, j'utilise généralement Joda. Un exemple si vous avez deux DateTimes, début et fin respectivement:Duration dur = new Duration(start, end); long millis = dur.getMillis();
TechTrip
1
J'aurais dû noter 2 façons d'utiliser les formateurs Joda. Première variation sur votre thème: DateTimeFormat.forPattern("mm:ss:SSS").print(new DateTime(time)); ou convertissez la durée en une période qui peut être automatiquement imprimée à l'aide d'un Joda PeriodFormatter. La conversion pourrait avoir une perte de précision si autre que la chronologie ISO. Supposons une durée représentée par la variable duration. Period period = duration.toPeriod().normalizedStandard(PeriodType.time()); PeriodFormat.getDefault().print(period)) La sortie est impressionnante: 1 seconde et 581 millisecondes, répondant à la question principale ci-dessus.
TechTrip
2
Un peu tard ici :) Mais n'auriez-vous pas besoin de mettre simpleDateFormat.setTimezone (TimeZone.getTimeZone ("GMT")) ici à moins que ce ne soit votre fuseau horaire réel?
Olle Söderström
@ OlleSöderström Il y a en effet un problème avec le fuseau horaire ici. Mais en le réglant sur GMT ou UTC, la partie horaire est 12 au lieu de 0 pour toutes les durées inférieures à 1 heure.
Episodex
2
Le fuseau horaire n'est pas le seul problème ici ... cette réponse est trompeuse et pourrait sérieusement confondre les débutants Java. Même en ignorant les supports externes redondants, le PO a demandé comment présenter une durée (une différence entre deux points dans le temps, mesurée en ms). Appeler cette durée "temps" et la traiter comme un décalage depuis le 1er janvier 1970 juste pour le formatage de ses composants plus petits est tout simplement ... faux imo. De plus, la même approche avait déjà été suggérée 3 ans plus tôt par cette réponse (voir les commentaires ici pour plus de détails sur les problèmes de fuseau horaire).
Amos M. Carpenter
36

Uhm ... combien de millisecondes sont en une seconde? Et dans une minute? La division n'est pas si difficile.

int seconds = (int) ((milliseconds / 1000) % 60);
int minutes = (int) ((milliseconds / 1000) / 60);

Continuez comme ça pendant des heures, des jours, des semaines, des mois, des années, des décennies, peu importe.

Bombe
la source
2
En fait, faire cela pour une durée supérieure à une heure n'est pas une bonne idée car les résultats peuvent être erronés / peu intuitifs lorsque l'heure d'été (jours de 23 ou 24 heures) ou des années bissextiles sont impliquées. Si je lis "X arrivera dans 1 an / mois", je m'attendrais à ce que ce soit la même date et l'heure.
Michael Borgwardt
5
System.currentTimeMillis () est immunisé contre les DST donc cela ne sera pas confondu par des heures supplémentaires ou manquantes. Si vous devez montrer la différence entre deux dates spécifiques, il vaut mieux construire des objets Date avec l'heure donnée et montrer la différence entre ces deux dates.
Bombe
1
Au-delà des semaines, elle n'est pas définie, car la durée du mois est variable. Donc, en effet, vous devez calculer par rapport à une référence de temps donnée.
PhiLho
31

Utilisation du package java.time dans Java 8:

Instant start = Instant.now();
Thread.sleep(63553);
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

La sortie est au format de durée ISO 8601 : PT1M3.553S(1 minute et 3,553 secondes).

Vitalii Fedorenko
la source
1
(ANDROID) Nécessite le niveau API 26
Someone Somewhere
1
@SomeoneSomewhere Pour Android sous API niveau 26, utilisez le backport, voir Comment utiliser ThreeTenABP dans Android Project .
Ole VV
1
C'est génial :) merci pour le heads-up!
Someone Somewhere
27

Je ne tirerais pas la dépendance supplémentaire juste pour cela (la division n'est pas si difficile, après tout), mais si vous utilisez Commons Lang de toute façon, il y a le DurationFormatUtils .

Exemple d'utilisation (adapté d' ici ):

import org.apache.commons.lang3.time.DurationFormatUtils

public String getAge(long value) {
    long currentTime = System.currentTimeMillis();
    long age = currentTime - value;
    String ageString = DurationFormatUtils.formatDuration(age, "d") + "d";
    if ("0d".equals(ageString)) {
        ageString = DurationFormatUtils.formatDuration(age, "H") + "h";
        if ("0h".equals(ageString)) {
            ageString = DurationFormatUtils.formatDuration(age, "m") + "m";
            if ("0m".equals(ageString)) {
                ageString = DurationFormatUtils.formatDuration(age, "s") + "s";
                if ("0s".equals(ageString)) {
                    ageString = age + "ms";
                }
            }
        }
    }
    return ageString;
}   

Exemple:

long lastTime = System.currentTimeMillis() - 2000;
System.out.println("Elapsed time: " + getAge(lastTime)); 

//Output: 2s

Remarque : Pour obtenir des millis de deux objets LocalDateTime, vous pouvez utiliser:

long age = ChronoUnit.MILLIS.between(initTime, LocalDateTime.now())
Thilo
la source
1
Génial, je me demandais simplement s'il y avait une bibliothèque robuste qui incluait ce genre de choses.
Lajcik
Comme un lien n'est généralement pas très utile, j'ai ajouté un exemple sur la façon dont il peut être utilisé.
lepe
26

Vous pouvez soit répartir les divisions, soit utiliser l' API SimpleDateFormat .

long start = System.currentTimeMillis();
// do your work...
long elapsed = System.currentTimeMillis() - start;
DateFormat df = new SimpleDateFormat("HH 'hours', mm 'mins,' ss 'seconds'");
df.setTimeZone(TimeZone.getTimeZone("GMT+0"));
System.out.println(df.format(new Date(elapsed)));

Edit by Bombe : Il a été montré dans les commentaires que cette approche ne fonctionne que pour des durées plus petites (c'est-à-dire moins d'une journée).

cadrian
la source
Sensationnel. C'est un hack diabolique dépendant du fuseau horaire. Il se brisera sans pitié lorsque vous avez un décalage de fuseau horaire qui n'est pas un multiple de 60 minutes (et nous avons quelques-uns de ces fuseaux horaires décalés de 30 minutes dans le monde).
Bombe
En outre, il se cassera tout aussi mal dès que vous incluez les heures dans la chaîne de formatage et ne sont pas à GMT + 0, pour les mêmes raisons.
Bombe
Nous faisons? Vraiment? Où? Sans doute, je n'en ai jamais entendu parler auparavant - un nouvel écueil à considérer ;-)
Treb
Oui. Consultez la «Liste des fuseaux horaires» sur Wikipédia, par exemple le Népal est à GMT + 05: 45.
Bombe
2
cadrian, maintenant il ne fonctionnera que pour des durées inférieures à une journée. Le nombre d'heures sera toujours compris entre 0 et 23 inclus.
Bombe
21

Juste pour ajouter plus d'informations si vous souhaitez formater comme: HH: mm: ss

0 <= HH <= infini

0 <= mm <60

0 <= ss <60

utilisez ceci:

int h = (int) ((startTimeInMillis / 1000) / 3600);
int m = (int) (((startTimeInMillis / 1000) / 60) % 60);
int s = (int) ((startTimeInMillis / 1000) % 60);

Je viens d'avoir ce problème maintenant et je l'ai compris

fredcrs
la source
1
Meilleure réponse ici. Pourquoi tout le monde veut-il compliquer les choses? Ce sont des mathématiques simples, les amis.
Lambart
11

Je pense que la meilleure façon est:

String.format("%d min, %d sec", 
    TimeUnit.MILLISECONDS.toSeconds(length)/60,
    TimeUnit.MILLISECONDS.toSeconds(length) % 60 );
Xtera
la source
pendant des minutes, vous pouvez utiliser TimeUnit.MILLISECONDS.toMinutes (durée)
EminenT
11

Solution la plus courte:

Voici probablement le plus court qui traite également des fuseaux horaires.

System.out.printf("%tT", millis-TimeZone.getDefault().getRawOffset());

Quelles sorties par exemple:

00:18:32

Explication:

%tTest l'heure au format 24 heures %tH:%tM:%tS.

%tTaccepte également les longs comme entrée, donc pas besoin de créer un Date.printf()affichera simplement l'heure spécifiée en millisecondes, mais dans le fuseau horaire actuel, nous devons donc soustraire le décalage brut du fuseau horaire actuel afin que 0 millisecondes soit 0 heure et non la valeur de décalage horaire du fuseau horaire actuel.

Note # 1: Si vous avez besoin du résultat en tant que String, vous pouvez l'obtenir comme ceci:

String t = String.format("%tT", millis-TimeZone.getDefault().getRawOffset());

Remarque n ° 2: cela ne donne un résultat correct que s'il millisest inférieur à un jour car la partie jour n'est pas incluse dans la sortie.

icza
la source
C'est un excellent raccourci, mais quand je l'utilise, je n'obtiens pas les résultats escomptés. J'ai donc: long millis = 8398;et quand je passe ça à String.format("%tT", millis)ma sortie c'est 19:00:08. D'où vient le 19?
Nelda.techspiress
1
@ Nelda.techspiress C'est le décalage de votre fuseau horaire. Vous devez en soustraire TimeZone.getDefault().getRawOffset(), exactement comme écrit dans la réponse:String.format("%tT", millis-TimeZone.getDefault().getRawOffset())
icza
qui s'en est occupé. Merci d'avoir clarifié.
Nelda.techspiress
8

Joda-Time

Utilisation de Joda-Time :

DateTime startTime = new DateTime();

// do something

DateTime endTime = new DateTime();
Duration duration = new Duration(startTime, endTime);
Period period = duration.toPeriod().normalizedStandard(PeriodType.time());
System.out.println(PeriodFormat.getDefault().print(period));
dogbane
la source
1
Pas besoin de ça PeriodFormatdans la dernière ligne. Appelez simplement Period::toStringpour obtenir une durée ISO 8601 chaîne de par défaut.
Basil Bourque
8

Revisitant la contribution de @ brent-nash, nous pourrions utiliser la fonction module au lieu de soustractions et utiliser la méthode String.format pour la chaîne de résultat:

  /**
   * Convert a millisecond duration to a string format
   * 
   * @param millis A duration to convert to a string form
   * @return A string of the form "X Days Y Hours Z Minutes A Seconds B Milliseconds".
   */
   public static String getDurationBreakdown(long millis) {
       if (millis < 0) {
          throw new IllegalArgumentException("Duration must be greater than zero!");
       }

       long days = TimeUnit.MILLISECONDS.toDays(millis);
       long hours = TimeUnit.MILLISECONDS.toHours(millis) % 24;
       long minutes = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
       long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
       long milliseconds = millis % 1000;

       return String.format("%d Days %d Hours %d Minutes %d Seconds %d Milliseconds",
                            days, hours, minutes, seconds, milliseconds);
   }
Jose Tepedino
la source
6

pour Android sous API 9

(String.format("%d hr %d min, %d sec", millis/(1000*60*60), (millis%(1000*60*60))/(1000*60), ((millis%(1000*60*60))%(1000*60))/1000)) 
Pradeep
la source
5

Pour les petits temps, moins d'une heure, je préfère:

long millis = ...

System.out.printf("%1$TM:%1$TS", millis);
// or
String str = String.format("%1$TM:%1$TS", millis);

pour des intervalles plus longs:

private static final long HOUR = TimeUnit.HOURS.toMillis(1);
...
if (millis < HOUR) {
    System.out.printf("%1$TM:%1$TS%n", millis);
} else {
    System.out.printf("%d:%2$TM:%2$TS%n", millis / HOUR, millis % HOUR);
}
user85421
la source
C'est une indication précieuse, il existe de nombreuses possibilités pour la date et l'heure avec l'API Java Formatter ( docs.oracle.com/javase/8/docs/api/java/util/Formatter.html )! Vous pouvez également avoir le résultat de la condition else avec: System.out.printf ("% 1 $ tH:% 1 $ tM:% 1 $ tS% n", millis); ou même System.out.printf ("% 1 $ tT% n", millis);
Jose Tepedino
@JoseTepedino mais vous savez que %tH ne montre que de 0 à 23 heures? Cela signifie que, par exemple, 24 heures seront affichées comme 00, 25 heures comme 01... même valable pour %tT- jours seront ignorées en silence. Bien sûr, il pourrait également y avoir des jours affichés, mais ce serait une exagération pour le problème que j'ai eu quand j'ai écrit ceci (en 2011) [:-)
user85421
Je vois ... cela ne fonctionnerait vraiment que pour des temps inférieurs à une journée (24h). Je vous remercie.
Jose Tepedino
5

Mon calcul simple:

String millisecToTime(int millisec) {
    int sec = millisec/1000;
    int second = sec % 60;
    int minute = sec / 60;
    if (minute >= 60) {
        int hour = minute / 60;
        minute %= 60;
        return hour + ":" + (minute < 10 ? "0" + minute : minute) + ":" + (second < 10 ? "0" + second : second);
    }
    return minute + ":" + (second < 10 ? "0" + second : second);
}

Bon codage :)

Shohan Ahmed Sijan
la source
Je suppose que long est plus approprié pour cette fonction car System.currentTimeMillis () renvoie une valeur longue.
2018 à 3h08
Ce n'est pas correct, avez-vous vérifié la sortie?
Jorgesys
4

Voici une réponse basée sur la réponse de Brent Nash, espérons que cela aide!

public static String getDurationBreakdown(long millis)
{
    String[] units = {" Days ", " Hours ", " Minutes ", " Seconds "};
    Long[] values = new Long[units.length];
    if(millis < 0)
    {
        throw new IllegalArgumentException("Duration must be greater than zero!");
    }

    values[0] = TimeUnit.MILLISECONDS.toDays(millis);
    millis -= TimeUnit.DAYS.toMillis(values[0]);
    values[1] = TimeUnit.MILLISECONDS.toHours(millis);
    millis -= TimeUnit.HOURS.toMillis(values[1]);
    values[2] = TimeUnit.MILLISECONDS.toMinutes(millis);
    millis -= TimeUnit.MINUTES.toMillis(values[2]);
    values[3] = TimeUnit.MILLISECONDS.toSeconds(millis);

    StringBuilder sb = new StringBuilder(64);
    boolean startPrinting = false;
    for(int i = 0; i < units.length; i++){
        if( !startPrinting && values[i] != 0)
            startPrinting = true;
        if(startPrinting){
            sb.append(values[i]);
            sb.append(units[i]);
        }
    }

    return(sb.toString());
}
Reda Bouaichi
la source
4
    long startTime = System.currentTimeMillis();
    // do your work...
    long endTime=System.currentTimeMillis();
    long diff=endTime-startTime;       
    long hours=TimeUnit.MILLISECONDS.toHours(diff);
    diff=diff-(hours*60*60*1000);
    long min=TimeUnit.MILLISECONDS.toMinutes(diff);
    diff=diff-(min*60*1000);
    long seconds=TimeUnit.MILLISECONDS.toSeconds(diff);
    //hour, min and seconds variables contains the time elapsed on your work
Fathah Rehman P
la source
3
La formule de la ligne 6 est incorrecte. diff=diff-(hours*60*1000);devrait être diff=diff-(hours*60*60*1000);. J'ai essayé de le modifier, mais la politique de modification agaçante de StackOverflow dit que ce n'est pas assez de caractères pour une modification.
quux00
4

Premièrement, System.currentTimeMillis()et Instant.now()ne sont pas idéales pour le chronométrage. Ils signalent tous deux l'heure de l'horloge murale, que l'ordinateur ne connaît pas précisément, et qui peut se déplacer de manière irrégulière, y compris en reculant si, par exemple, le démon NTP corrige l'heure du système. Si votre chronométrage se produit sur une seule machine, vous devez plutôt utiliser System.nanoTime () .

Deuxièmement, à partir de Java 8, java.time.Duration est le meilleur moyen de représenter une durée:

long start = System.nanoTime();
// do things...
long end = System.nanoTime();
Duration duration = Duration.ofNanos(end - start);
System.out.println(duration); // Prints "PT18M19.511627776S"
System.out.printf("%d Hours %d Minutes %d Seconds%n",
        duration.toHours(), duration.toMinutes() % 60, duration.getSeconds() % 60);
// prints "0 Hours 18 Minutes 19 Seconds"
MikeFHay
la source
3

Si vous savez que le décalage horaire serait inférieur à une heure, vous pouvez utiliser le code suivant:

    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();

    c2.add(Calendar.MINUTE, 51);

    long diff = c2.getTimeInMillis() - c1.getTimeInMillis();

    c2.set(Calendar.MINUTE, 0);
    c2.set(Calendar.HOUR, 0);
    c2.set(Calendar.SECOND, 0);

    DateFormat df = new SimpleDateFormat("mm:ss");
    long diff1 = c2.getTimeInMillis() + diff;
    System.out.println(df.format(new Date(diff1)));

Il en résultera: 51:00

Gourav Singla
la source
3

Cette réponse est similaire à certaines réponses ci-dessus. Cependant, je pense que ce serait bénéfique parce que, contrairement aux autres réponses, cela supprimera toutes les virgules ou espaces et gèrera les abréviations.

/**
 * Converts milliseconds to "x days, x hours, x mins, x secs"
 * 
 * @param millis
 *            The milliseconds
 * @param longFormat
 *            {@code true} to use "seconds" and "minutes" instead of "secs" and "mins"
 * @return A string representing how long in days/hours/minutes/seconds millis is.
 */
public static String millisToString(long millis, boolean longFormat) {
    if (millis < 1000) {
        return String.format("0 %s", longFormat ? "seconds" : "secs");
    }
    String[] units = {
            "day", "hour", longFormat ? "minute" : "min", longFormat ? "second" : "sec"
    };
    long[] times = new long[4];
    times[0] = TimeUnit.DAYS.convert(millis, TimeUnit.MILLISECONDS);
    millis -= TimeUnit.MILLISECONDS.convert(times[0], TimeUnit.DAYS);
    times[1] = TimeUnit.HOURS.convert(millis, TimeUnit.MILLISECONDS);
    millis -= TimeUnit.MILLISECONDS.convert(times[1], TimeUnit.HOURS);
    times[2] = TimeUnit.MINUTES.convert(millis, TimeUnit.MILLISECONDS);
    millis -= TimeUnit.MILLISECONDS.convert(times[2], TimeUnit.MINUTES);
    times[3] = TimeUnit.SECONDS.convert(millis, TimeUnit.MILLISECONDS);
    StringBuilder s = new StringBuilder();
    for (int i = 0; i < 4; i++) {
        if (times[i] > 0) {
            s.append(String.format("%d %s%s, ", times[i], units[i], times[i] == 1 ? "" : "s"));
        }
    }
    return s.toString().substring(0, s.length() - 2);
}

/**
 * Converts milliseconds to "x days, x hours, x mins, x secs"
 * 
 * @param millis
 *            The milliseconds
 * @return A string representing how long in days/hours/mins/secs millis is.
 */
public static String millisToString(long millis) {
    return millisToString(millis, false);
}
Jared Rummler
la source
3

Il ya un problème. Lorsque les millisecondes sont égales à 59999, elles durent en réalité 1 minute, mais elles seront calculées en 59 secondes et 999 millisecondes seront perdues.

Voici une version modifiée basée sur les réponses précédentes, qui peut résoudre cette perte:

public static String formatTime(long millis) {
    long seconds = Math.round((double) millis / 1000);
    long hours = TimeUnit.SECONDS.toHours(seconds);
    if (hours > 0)
        seconds -= TimeUnit.HOURS.toSeconds(hours);
    long minutes = seconds > 0 ? TimeUnit.SECONDS.toMinutes(seconds) : 0;
    if (minutes > 0)
        seconds -= TimeUnit.MINUTES.toSeconds(minutes);
    return hours > 0 ? String.format("%02d:%02d:%02d", hours, minutes, seconds) : String.format("%02d:%02d", minutes, seconds);
}
Hexise
la source
2

C'est plus simple en Java 9:

    Duration elapsedTime = Duration.ofMillis(millisDiff );
    String humanReadableElapsedTime = String.format(
            "%d hours, %d mins, %d seconds",
            elapsedTime.toHours(),
            elapsedTime.toMinutesPart(),
            elapsedTime.toSecondsPart());

Cela produit une chaîne comme 0 hours, 39 mins, 9 seconds.

Si vous souhaitez arrondir à des secondes entières avant de formater:

    elapsedTime = elapsedTime.plusMillis(500).truncatedTo(ChronoUnit.SECONDS);

Pour supprimer les heures si elles sont égales à 0:

    long hours = elapsedTime.toHours();
    String humanReadableElapsedTime;
    if (hours == 0) {
        humanReadableElapsedTime = String.format(
                "%d mins, %d seconds",
                elapsedTime.toMinutesPart(),
                elapsedTime.toSecondsPart());

    } else {
        humanReadableElapsedTime = String.format(
                "%d hours, %d mins, %d seconds",
                hours,
                elapsedTime.toMinutesPart(),
                elapsedTime.toSecondsPart());
    }

Maintenant on peut avoir par exemple 39 mins, 9 seconds.

Pour imprimer les minutes et les secondes avec un zéro devant pour les faire toujours deux chiffres, il suffit d'insérer 02dans les spécificateurs de format appropriés, ainsi:

    String humanReadableElapsedTime = String.format(
            "%d hours, %02d mins, %02d seconds",
            elapsedTime.toHours(),
            elapsedTime.toMinutesPart(),
            elapsedTime.toSecondsPart());

Maintenant, nous pouvons avoir par exemple 0 hours, 39 mins, 09 seconds.

Ole VV
la source
Toute mise en forme pour supprimer les heures / minutes / secondes lorsqu'un nombre précédent est 0? Je veux dire qu'il est réalisable avec une condition if else, mais qu'en est-il de l'existence d'un tel formatage de chaîne ou de quelque chose de proche, y en a-t-il?
Farid
1
Non, désolé, @FARID, vous avez besoin if- elselà.
Ole VV
1

pour les chaînes correctes ("1 heure, 3 sec", "3 min" mais pas "0 heure, 0 min, 3 sec") j'écris ce code:

int seconds = (int)(millis / 1000) % 60 ;
int minutes = (int)((millis / (1000*60)) % 60);
int hours = (int)((millis / (1000*60*60)) % 24);
int days = (int)((millis / (1000*60*60*24)) % 365);
int years = (int)(millis / 1000*60*60*24*365);

ArrayList<String> timeArray = new ArrayList<String>();

if(years > 0)   
    timeArray.add(String.valueOf(years)   + "y");

if(days > 0)    
    timeArray.add(String.valueOf(days) + "d");

if(hours>0)   
    timeArray.add(String.valueOf(hours) + "h");

if(minutes>0) 
    timeArray.add(String.valueOf(minutes) + "min");

if(seconds>0) 
    timeArray.add(String.valueOf(seconds) + "sec");

String time = "";
for (int i = 0; i < timeArray.size(); i++) 
{
    time = time + timeArray.get(i);
    if (i != timeArray.size() - 1)
        time = time + ", ";
}

if (time == "")
  time = "0 sec";
John
la source
1

J'ai modifié la réponse de @MyKuLLSKI et ajouté le support de la plurlisation. J'ai pris quelques secondes car je n'en avais pas besoin, mais n'hésitez pas à le rajouter si vous en avez besoin.

public static String intervalToHumanReadableTime(int intervalMins) {

    if(intervalMins <= 0) {
        return "0";
    } else {

        long intervalMs = intervalMins * 60 * 1000;

        long days = TimeUnit.MILLISECONDS.toDays(intervalMs);
        intervalMs -= TimeUnit.DAYS.toMillis(days);
        long hours = TimeUnit.MILLISECONDS.toHours(intervalMs);
        intervalMs -= TimeUnit.HOURS.toMillis(hours);
        long minutes = TimeUnit.MILLISECONDS.toMinutes(intervalMs);

        StringBuilder sb = new StringBuilder(12);

        if (days >= 1) {
            sb.append(days).append(" day").append(pluralize(days)).append(", ");
        }

        if (hours >= 1) {
            sb.append(hours).append(" hour").append(pluralize(hours)).append(", ");
        }

        if (minutes >= 1) {
            sb.append(minutes).append(" minute").append(pluralize(minutes));
        } else {
            sb.delete(sb.length()-2, sb.length()-1);
        }

        return(sb.toString());          

    }

}

public static String pluralize(long val) {
    return (Math.round(val) > 1 ? "s" : "");
}
bitstream
la source
int intervalMins vs long millis
Kiquenet
1

J'ai couvert cela dans une autre réponse mais vous pouvez le faire:

public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {
    long diffInMillies = date2.getTime() - date1.getTime();
    List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
    Collections.reverse(units);
    Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
    long milliesRest = diffInMillies;
    for ( TimeUnit unit : units ) {
        long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;
        result.put(unit,diff);
    }
    return result;
}

La sortie est quelque chose comme Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0} , avec les unités commandées.

C'est à vous de comprendre comment internationaliser ces données en fonction des paramètres régionaux cibles.

Sébastien Lorber
la source
1

Utilisez java.util.concurrent.TimeUnit et utilisez cette méthode simple:

private static long timeDiff(Date date, Date date2, TimeUnit unit) {
    long milliDiff=date2.getTime()-date.getTime();
    long unitDiff = unit.convert(milliDiff, TimeUnit.MILLISECONDS);
    return unitDiff; 
}

Par exemple:

SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd HH:mm:ss");  
Date firstDate = sdf.parse("06/24/2017 04:30:00");
Date secondDate = sdf.parse("07/24/2017 05:00:15");
Date thirdDate = sdf.parse("06/24/2017 06:00:15");

System.out.println("days difference: "+timeDiff(firstDate,secondDate,TimeUnit.DAYS));
System.out.println("hours difference: "+timeDiff(firstDate,thirdDate,TimeUnit.HOURS));
System.out.println("minutes difference: "+timeDiff(firstDate,thirdDate,TimeUnit.MINUTES));
System.out.println("seconds difference: "+timeDiff(firstDate,thirdDate,TimeUnit.SECONDS));
Aramis Rodríguez Blanco
la source