Comment convertir les millisecondes au format «hh: mm: ss»?

184

Je suis confus. Après être tombé sur ce fil, j'ai essayé de comprendre comment formater un compte à rebours qui avait le format hh:mm:ss.

Voici ma tentative -

//hh:mm:ss
String.format("%02d:%02d:%02d", 
    TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) - 
    TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));   

Donc, quand j'essaie une valeur comme 3600000ms, j'obtiens 01:59:00, ce qui est faux car il devrait l'être 01:00:00. Il y a évidemment quelque chose qui cloche dans ma logique, mais pour le moment, je ne vois pas ce que c'est!

Quelqu'un peut-il aider?

Éditer -

Corrigé. Voici la bonne façon de formater les millisecondes pour hh:mm:ssformater -

//hh:mm:ss
String.format("%02d:%02d:%02d", 
    TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) - 
    TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
    TimeUnit.MILLISECONDS.toSeconds(millis) - 
    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))));

Le problème était le suivant TimeUnit.MINUTES.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)). Cela aurait dû être ça à la TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis))place.

mre
la source
1
3 600 000 millisecondes correspondent à 3 600 secondes, 60 minutes ou 1 heure. Ça ne devrait pas l'être 00:59:59, ça devrait l'être 01:00:00.
Borealid

Réponses:

355

Vous étiez vraiment proche:

String.format("%02d:%02d:%02d", 
TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) -  
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), // The change is in this line
TimeUnit.MILLISECONDS.toSeconds(millis) - 
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));   

Vous convertissiez des heures en millissecondes en utilisant des minutes au lieu d' heures .

BTW, j'aime votre utilisation de l' TimeUnitAPI :)

Voici un code de test:

public static void main(String[] args) throws ParseException {
    long millis = 3600000;
    String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
            TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
    System.out.println(hms);
}

Production:

01:00:00

J'ai réalisé que mon code ci-dessus peut être grandement simplifié en utilisant une division de module au lieu d'une soustraction:

String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
    TimeUnit.MILLISECONDS.toMinutes(millis) % TimeUnit.HOURS.toMinutes(1),
    TimeUnit.MILLISECONDS.toSeconds(millis) % TimeUnit.MINUTES.toSeconds(1));

Toujours en utilisant l' TimeUnitAPI pour toutes les valeurs magiques, et donne exactement le même résultat.

Bohème
la source
2
Amen, comme la façon dont vous utilisez TimeUnit API :)
Dheeraj Bhaskar
2
Ce n'est pas une bonne idée de réinventer la roue! La réponse de Triton Man est une meilleure solution.
محمدباقر
5
@ محمدباقر Mais l'autre réponse utilise une bibliothèque externe, alors que mon code utilise uniquement le JDK principal. Cela dépend de vos besoins - par exemple, vous ne pourrez peut-être pas utiliser une bibliothèque externe. L'autre réponse est cependant bonne.
Bohème
2
@Ozuf ajoute .replaceAll("^00:", "")ou .replaceAll("^00:(00:)?", "")supprime des minutes ainsi que des heures si les deux sont à zéro.
Bohème
2
@Ozuf vous obtenez "15:00"et "10:00:23"respectivement; seuls les zéros non significatifs sont supprimés, car la correspondance est ancrée au début de l'entrée par ^.
Bohème
77

La méthode générique pour cela est assez simple:

public static String convertSecondsToHMmSs(long seconds) {
    long s = seconds % 60;
    long m = (seconds / 60) % 60;
    long h = (seconds / (60 * 60)) % 24;
    return String.format("%d:%02d:%02d", h,m,s);
}
Arets Paeglis
la source
1
@ Javaman59, vouliez-vous dire String.format("% 02 d:%02d:%02d", h,m,s) ?
KarenAnne
2
@KarenAnne. Cela dépend si vous voulez, par exemple, "03:59:59" ou "3:59:59".
Stephen Hosking
2
Le temps est en millisecondes, vous devez multiplier les secondes par 1000
Apurva
5
l'auteur a demandé des millisecondes, pas des secondes!
user924
59

Si vous utilisez apache commons:

DurationFormatUtils.formatDuration(timeInMS, "HH:mm:ss,SSS");
Homme Triton
la source
4
Raccourci:DurationFormatUtils.formatDurationHMS(timeInMS);
Aroniaina
@Jorgesys Pourquoi sont-ils obsolètes?
Piovezan
ils ne sont pas obsolètes.
Triton Man
26

J'ai utilisé ceci:

String.format("%1$tH:%1$tM:%1$tS.%1$tL", millis);

Voir la description de la classe Formatter .

Voir l' exemple exécutable avec une entrée de 2400 ms.

ZuluM
la source
Cela semble ne pas fonctionner, je le teste simplement en passant 100, 1000, 1200 et il répond comme 05:30:00 , 05:30:01 , 05:30:01 .
CoDe
2
@CoDe, cela fonctionne pour votre fuseau horaire. Vous devez être dans un fuseau horaire différent de UTC. dépend duString.format() fuseau horaire . La bonne réponse idéale, cependant, doit être indépendante du fuseau horaire .
Derek Mahar
@CoDe, il affiche les heures qui correspondent à votre fuseau horaire qui doit être différent de UTC. dépend duString.format() fuseau horaire . La bonne réponse idéale, cependant, doit être indépendante du fuseau horaire .
Derek Mahar
25
// New date object from millis
Date date = new Date(millis);
// formattter 
SimpleDateFormat formatter= new SimpleDateFormat("HH:mm:ss.SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// Pass date object
String formatted = formatter.format(date );

Voir l' exemple exécutable en utilisant une entrée de 1200 ms.

Vinay Lodha
la source
3
Cela produirait des résultats incorrects pour des périodes de plus d'une journée. Cela ramènerait le nombre d'heures de 23 à 0, ce qui n'est probablement pas souhaitable ici.
Kenster
Pas de copain ... Je pense que ça fonctionnerait toujours de la même manière. essayez avec la date d'aujourd'hui
Vinay Lodha
1
SimpleDateFormat sdf = new SimpleDateFormat ("hh: mm aa"); au cas où quelqu'un voudrait au format 12 heures avec am / pm
Ajji
14
DateFormat df = new SimpleDateFormat("HH:mm:ss");
String formatted = df.format(aDateObject);
Gabriel Belingueres
la source
1
Même réponse que stackoverflow.com/questions/9027317/… avec le même problème pour une durée supérieure à 1 jour
OneWorld
Cela dépend également du fuseau horaire, ce qui signifie que le résultat sera différent lorsqu'il sera exécuté dans différents fuseaux horaires.
Derek Mahar le
10

Résultats des tests pour les 4 implémentations

Devoir faire beaucoup de formatage pour des données énormes, il fallait les meilleures performances, voici donc les résultats (surprenants):

pour (int i = 0; i <1000000; i ++) {FUNCTION_CALL}

Durées:

  • combinaison Format : 196 millis
  • formatDurée: 272 millis
  • apacheFormat: 754 millis
  • formatTimeUnit: 2216 millis

    public static String apacheFormat(long millis) throws ParseException {
        return DurationFormatUtils.formatDuration(millis, "HH:mm:ss");
    }
    
    public static String formatTimeUnit(long millis) throws ParseException {
    String formatted = String.format(
            "%02d:%02d:%02d",
            TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis)
                    - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
            TimeUnit.MILLISECONDS.toSeconds(millis)
                    - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
        return formatted;
    }
    
    public static String formatDuration(final long millis) {
        long seconds = (millis / 1000) % 60;
        long minutes = (millis / (1000 * 60)) % 60;
        long hours = millis / (1000 * 60 * 60);
    
        StringBuilder b = new StringBuilder();
        b.append(hours == 0 ? "00" : hours < 10 ? String.valueOf("0" + hours) : 
        String.valueOf(hours));
        b.append(":");
        b.append(minutes == 0 ? "00" : minutes < 10 ? String.valueOf("0" + minutes) :     
        String.valueOf(minutes));
        b.append(":");
        b.append(seconds == 0 ? "00" : seconds < 10 ? String.valueOf("0" + seconds) : 
        String.valueOf(seconds));
        return b.toString();
    }
    
    public static String combinationFormatter(final long millis) {
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis)
                - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis));
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis)
                - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis));
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
    
        StringBuilder b = new StringBuilder();
        b.append(hours == 0 ? "00" : hours < 10 ? String.valueOf("0" + hours) : 
        String.valueOf(hours));
        b.append(":");
        b.append(minutes == 0 ? "00" : minutes < 10 ? String.valueOf("0" + minutes) : 
        String.valueOf(minutes));
            b.append(":");
        b.append(seconds == 0 ? "00" : seconds < 10 ? String.valueOf("0" + seconds) : 
        String.valueOf(seconds));
        return b.toString(); 
     }
MariusA
la source
Quelle est la fiabilité des mesures comme celles-ci? Je n'ai jamais vraiment compris le processus.
mre
Dans ma situation où des milliers d'objets sont créés successivement, ce test me semble assez utile. OK, ne définissant pas seulement quelques chaînes, mais créant des objets qui ont un champ une chaîne formatée.
MariusA
@marius vous vous êtes donné la peine d'utiliser StringBuilderpuis faites l'erreur d'utiliser "0" + nombre de type "ruine". Le GC de @mre JVM est extrêmement bon pour allouer et collecter de nombreux objets de courte durée, pas de souci. Je suis allé String.formatsans logique de tête zéro à gérer.
escape-llc
7

cela a fonctionné pour moi, avec kotlin

fun formatToDigitalClock(miliSeconds: Long): String {
        val hours = TimeUnit.MILLISECONDS.toHours(miliSeconds).toInt() % 24
        val minutes = TimeUnit.MILLISECONDS.toMinutes(miliSeconds).toInt() % 60
        val seconds = TimeUnit.MILLISECONDS.toSeconds(miliSeconds).toInt() % 60
        return when {
            hours > 0 -> String.format("%d:%02d:%02d", hours, minutes, seconds)
            minutes > 0 -> String.format("%02d:%02d", minutes, seconds)
            seconds > 0 -> String.format("00:%02d", seconds)
            else -> {
                "00:00"
            }
        }
    }
Devix
la source
A parfaitement fonctionné pour moi. Cela devrait être la meilleure réponse car il gère zéro heure
vNext
6

En suivant la réponse de Bohemian, nous n'avons pas besoin d'utiliser TimeUnit pour trouver une valeur connue. Un code beaucoup plus optimal serait

String hms = String.format("%02d:%02d:%02d", millisLeft/(3600*1000),
                    millisLeft/(60*1000) % 60,
                    millisLeft/1000 % 60);

J'espère que ça aide

Aalin
la source
J'aime le plus ta réponse! Juste des maths simples. Btw dans mon cas, j'ai ajouté les millisecondes à la fin millisLeft%1000/10pour que nous obtenions le formathour:minutes:seconds:milliseconds
Lê Quang Duy
@ LêQuangDuy j'ai besoin de millisecondes en 3 chiffres comme 01: 24: 51,123 mais vous en hachez 3 enfin que faire?
naanu le
@naanu just usemillisLeft%1000
Lê Quang Duy
6
 public String millsToDateFormat(long mills) {

    Date date = new Date(mills);
    DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
    String dateFormatted = formatter.format(date);
    return dateFormatted; //note that it will give you the time in GMT+0
}
ctu
la source
La réponse dépend du fuseau horaire, ce qui signifie que le résultat sera différent lorsqu'il est exécuté dans différents fuseaux horaires.
Derek Mahar
6

Java 9

    Duration timeLeft = Duration.ofMillis(3600000);
    String hhmmss = String.format("%02d:%02d:%02d", 
            timeLeft.toHours(), timeLeft.toMinutesPart(), timeLeft.toSecondsPart());
    System.out.println(hhmmss);

Cela imprime:

01:00:00

Vous faites bien en laissant les méthodes de bibliothèque effectuer les conversions impliquées pour vous. java.time, l'API de date et d'heure Java moderne, ou plus précisément, sa Durationclasse le fait de manière plus élégante et moins sujette aux erreurs que TimeUnit.

Les méthodes toMinutesPartet que toSecondsPartj'ai utilisées ont été introduites dans Java 9.

Java 6, 7 et 8

    long hours = timeLeft.toHours();
    timeLeft = timeLeft.minusHours(hours);
    long minutes = timeLeft.toMinutes();
    timeLeft = timeLeft.minusMinutes(minutes);
    long seconds = timeLeft.toSeconds();
    String hhmmss = String.format("%02d:%02d:%02d", hours, minutes, seconds);
    System.out.println(hhmmss);

La sortie est la même que ci-dessus.

Question: Comment cela peut-il fonctionner dans Java 6 et 7?

  • Dans Java 8 et versions ultérieures et sur les appareils Android plus récents (à partir du niveau d'API 26, on me dit) java.timeest intégré.
  • Dans Java 6 et 7, obtenez le ThreeTen Backport, le backport des classes modernes (ThreeTen pour JSR 310; voir les liens en bas).
  • Sur Android (plus ancien), utilisez l'édition Android de ThreeTen Backport. Il s'appelle ThreeTenABP. Et assurez-vous d'importer les classes de date et d'heure à partir des org.threeten.bpsous-packages.

Liens

Ole VV
la source
5

Le code ci-dessous effectue la conversion dans les deux sens

23: 59: 58: 999 à 86398999

et que

86398999 à 23: 59: 58: 999


import java.util.concurrent.TimeUnit;

public class TimeUtility {

    public static void main(String[] args) {

        long currentDateTime = System.currentTimeMillis();

        String strTest = "23:59:58:999";
        System.out.println(strTest);

        long l = strToMilli(strTest);
        System.out.println(l);
        l += 1;
        String str = milliToString(l);
        System.out.println(str);
    }

    /**
     * convert a time string into the equivalent long milliseconds
     *
     * @param strTime string fomratted as HH:MM:SS:MSMS i.e. "23:59:59:999"
     * @return long integer like 86399999
     */
    public static long strToMilli(String strTime) {
        long retVal = 0;
        String hour = strTime.substring(0, 2);
        String min = strTime.substring(3, 5);
        String sec = strTime.substring(6, 8);
        String milli = strTime.substring(9, 12);
        int h = Integer.parseInt(hour);
        int m = Integer.parseInt(min);
        int s = Integer.parseInt(sec);
        int ms = Integer.parseInt(milli);

        String strDebug = String.format("%02d:%02d:%02d:%03d", h, m, s, ms);
        //System.out.println(strDebug);
        long lH = h * 60 * 60 * 1000;
        long lM = m * 60 * 1000;
        long lS = s * 1000;

        retVal = lH + lM + lS + ms;
        return retVal;
    }

    /**
     * convert time in milliseconds to the corresponding string, in case of day
     * rollover start from scratch 23:59:59:999 + 1 = 00:00:00:000
     *
     * @param millis the number of milliseconds corresponding to tim i.e.
     *               34137999 that can be obtained as follows;
     *               <p>
     *               long lH = h * 60 * 60 * 1000; //hour to milli
     *               <p>
     *               long lM = m * 60 * 1000; // minute to milli
     *               <p>
     *               long lS = s * 1000; //seconds to milli
     *               <p>
     *               millis = lH + lM + lS + ms;
     * @return a string formatted as HH:MM:SS:MSMS i.e. "23:59:59:999"
     */
    private static String milliToString(long millis) {

        long hrs = TimeUnit.MILLISECONDS.toHours(millis) % 24;
        long min = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
        long sec = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
        //millis = millis - (hrs * 60 * 60 * 1000); //alternative way
        //millis = millis - (min * 60 * 1000);
        //millis = millis - (sec * 1000);
        //long mls = millis ;
        long mls = millis % 1000;
        String toRet = String.format("%02d:%02d:%02d:%03d", hrs, min, sec, mls);
        //System.out.println(toRet);
        return toRet;
    }
}
Menzio Luca Fabrizio
la source
J'ai voté pour cette solution. Mettez simplement un point entre sec et ml. Et je ne sais pas pourquoi la gestion des heures et des dates est tellement difficile en Java. Les fonctions les plus utilisées doivent être déjà disponibles et faire partie de la classe.
Baruch Atta
5
        String string = String.format("%02d:%02d:%02d.%03d",
            TimeUnit.MILLISECONDS.toHours(millisecend), TimeUnit.MILLISECONDS.toMinutes(millisecend) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millisecend)),
            TimeUnit.MILLISECONDS.toSeconds(millisecend) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisecend)), millisecend - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millisecend)));

Format: 00: 00: 00.000

Exemple: 615605 Millisecend

00: 10: 15.605

Omid Naji
la source
5

La réponse marquée comme correcte comporte une petite erreur,

String myTime = String.format("%02d:%02d:%02d",
            TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) -
                    TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), // The change is in this line
            TimeUnit.MILLISECONDS.toSeconds(millis) -
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

par exemple ceci est un exemple de la valeur que j'obtiens:

417474:44:19

Voici la solution pour obtenir le bon format:

String myTime =  String.format("%02d:%02d:%02d",
                //Hours
                TimeUnit.MILLISECONDS.toHours(millis) -
                        TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(millis)),
                //Minutes
                TimeUnit.MILLISECONDS.toMinutes(millis) -
                        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                //Seconds
                TimeUnit.MILLISECONDS.toSeconds(millis) -
                        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

obtenir en conséquence un format correct:

18:44:19

une autre option pour obtenir le format hh:mm:ssest simplement:

   Date myDate = new Date(timeinMillis);
   SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
   String myTime = formatter.format(myDate);
Jorgesys
la source
4

J'ai essayé comme indiqué dans la première réponse. Cela fonctionne, mais moins m'a mis dans la confusion. Ma réponse par Groovy:

import static java.util.concurrent.TimeUnit.*

...

private static String formatElapsedTime(long millis) {

    int hrs = MILLISECONDS.toHours(millis) % 24
    int min = MILLISECONDS.toMinutes(millis) % 60
    int sec = MILLISECONDS.toSeconds(millis) % 60
    int mls = millis % 1000

    sprintf( '%02d:%02d:%02d (%03d)', [hrs, min, sec, mls])
}
Leonov
la source
3

Pour Kotlin

val hours = String.format("%02d", TimeUnit.MILLISECONDS.toHours(milSecs))
val minutes = String.format("%02d",
                        TimeUnit.MILLISECONDS.toMinutes(milSecs) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milSecs)))
val seconds = String.format("%02d",
                        TimeUnit.MILLISECONDS.toSeconds(milSecs) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milSecs)))

où, milSecsest en millisecondes

Kishan Solanki
la source
1

Eh bien, vous pouvez essayer quelque chose comme ça:

public String getElapsedTimeHoursMinutesSecondsString() {       
     long elapsedTime = getElapsedTime();  
     String format = String.format("%%0%dd", 2);  
     elapsedTime = elapsedTime / 1000;  
     String seconds = String.format(format, elapsedTime % 60);  
     String minutes = String.format(format, (elapsedTime % 3600) / 60);  
     String hours = String.format(format, elapsedTime / 3600);  
     String time =  hours + ":" + minutes + ":" + seconds;  
     return time;  
 }  

pour convertir des millisecondes en une valeur de temps

anonyme
la source