¿Cómo convertir milisegundos a "X minutos, x segundos" en Java?

573

Quiero registrar el tiempo usando System.currentTimeMillis()cuando un usuario comienza algo en mi programa. Cuando termine, restaré la corriente System.currentTimeMillis()de la startvariable y quiero mostrarles el tiempo transcurrido utilizando un formato legible para humanos, como "XX horas, XX minutos, XX segundos" o incluso "XX minutos, XX segundos" porque No es probable que le tome a alguien una hora.

¿Cuál es la mejor manera de hacer esto?

Haga clic en Upvote
fuente
55
Si tardan más de una hora, aún puede imprimir algo como; 90 minutos, 53 segundos
Peter Lawrey
1
mi respuesta llega 6 años tarde pero creo que es más genérica que las aceptadas: stackoverflow.com/a/35082080/82609
Sebastien Lorber
1
vea un ejemplo simple para convertir milisegundos en días, horas, minutos, segundos en Java
sumit kumar pradhan

Respuestas:

1229

Usa la java.util.concurrent.TimeUnitclase:

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

Nota: TimeUnites parte de la especificación Java 1.5, pero toMinutesse agregó a partir de Java 1.6.

Para agregar un cero inicial para los valores 0-9, simplemente haga:

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

Si TimeUnito toMinutesno son compatibles (como en Android antes de la versión 9 de API), use las siguientes ecuaciones:

int seconds = (int) (milliseconds / 1000) % 60 ;
int minutes = (int) ((milliseconds / (1000*60)) % 60);
int hours   = (int) ((milliseconds / (1000*60*60)) % 24);
//etc...
siddhadev
fuente
55
int meses = (int) ((flotante) días / 30.4368499f); int años = (int) ((flotante) días / 365.242199f);
Nathan Schwermann
77
Sugeriría usar mod 60 en lugar de restar los minutos, se ve más limpio. Sin embargo, uno necesita saber que 1 minuto = 60 segundos para hacer eso ... =)
Por Alexandersson
2
@AndreasDietrich SimpleDateFormat no funciona para las diferencias de tiempo, ya que solo devuelve la fecha de la época.
Muhammad Babar
55
int hours = (int) ((milliseconds / (1000*60*60)) % 24)esto no funciona! en cambio debería ser asíint hours = (int) (milliseconds / (1000*60*60)) ;
Muhammad Babar
55
Si alguien quiere un formato para archivos de video ( h: mm: ss ):String.format("%01d:%02d:%02d", hours, minutes, seconds);
kazy
124

Basado en la respuesta de @ siddhadev, escribí una función que convierte milisegundos a una cadena formateada:

   /**
     * 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 escribe el código
fuente
2
Debe hacer una comprobación allí para soltero / múltiple, para evitar este tipo de situación:1 Days 1 Hours 1 Minutes 1 Seconds
Daniel
77
Podríamos usar la función de módulo en lugar de la resta: 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; y también el método 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));

Huellas dactilares:

25: 36: 259

Damien
fuente
1
¡Me gusta el enfoque anterior, el mejor si nada es su simplicidad! Como estamos lidiando con tiempos y duraciones, normalmente uso Joda. Un ejemplo si tiene dos DateTimes, inicio y fin respectivamente:Duration dur = new Duration(start, end); long millis = dur.getMillis();
TechTrip
1
Debería haber notado 2 formas de usar los formateadores Joda. Primera variación de su tema: DateTimeFormat.forPattern("mm:ss:SSS").print(new DateTime(time)); o convierta la duración en un período que se pueda imprimir automáticamente con un Joda PeriodFormatter. La conversión podría tener una pérdida de precisión si no fuera la cronología ISO. Suponga una duración representada por la variable duration. Period period = duration.toPeriod().normalizedStandard(PeriodType.time()); PeriodFormat.getDefault().print(period)) La salida es impresionante: 1 segundo y 581 milisegundos, respondiendo la pregunta principal anterior.
TechTrip
2
Un poco tarde aquí :) Pero, ¿no necesitaría poner simpleDateFormat.setTimezone (TimeZone.getTimeZone ("GMT")) aquí a menos que esa sea su zona horaria real?
Olle Söderström
@ OlleSöderström De hecho, hay un problema con la zona horaria aquí. Pero establecerlo en GMT o UTC hace que la parte de la hora sea 12 en lugar de 0 para todas las duraciones de menos de 1 hora.
Episodex
2
La zona horaria no es el único problema aquí ... esta respuesta es engañosa y podría confundir seriamente a los novatos de Java. Incluso haciendo caso omiso de los corchetes externos redundantes, el OP preguntó cómo presentar una duración (una diferencia entre dos puntos en el tiempo, medida en ms). Llamar a esa duración "tiempo" y tratarlo como una compensación desde el 1 de enero de 1970 solo por el formato de sus componentes más pequeños es simplemente ... equivocado. Lo que es más, el mismo enfoque ya había sido sugerido 3 años antes por esta respuesta (ver comentarios allí para más detalles sobre problemas de zona horaria).
Amos M. Carpenter
36

Uhm ... ¿cuántos milisegundos hay en un segundo? ¿Y en un minuto? La división no es tan difícil.

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

Continúe así durante horas, días, semanas, meses, años, décadas, lo que sea.

Bombe
fuente
2
En realidad, hacer esto por más de una hora no es una buena idea ya que los resultados pueden ser incorrectos / poco intuitivos cuando se trata del horario de verano (días de 23 o 24 horas) o años bisiestos. Si leo "X ocurrirá en 1 año / mes", esperaría que fuera la misma fecha y hora.
Michael Borgwardt
55
System.currentTimeMillis () es inmune contra el horario de verano, por lo que esto no se verá confundido por horas adicionales o faltantes. Si necesita mostrar la diferencia entre dos fechas específicas, es mejor que construya objetos Date con la hora dada y muestre la diferencia entre esas dos.
Bombe
1
Más allá de las semanas, no está definido, ya que la duración del mes es variable. Entonces, de hecho, necesita calcular en relación con una referencia de tiempo dada.
PhiLho
31

Usando el paquete java.time en Java 8:

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

La salida está en formato de duración ISO 8601 : PT1M3.553S(1 minuto y 3.553 segundos).

Vitalii Fedorenko
fuente
1
(ANDROID) Requiere API nivel 26
Alguien en algún lugar
1
@SomeoneSomewhere Para Android bajo el nivel 26 de API, use el backport, vea Cómo usar ThreeTenABP en Android Project .
Ole VV
1
Eso es increíble :) gracias por el aviso!
Alguien en algún lugar
27

No obtendría la dependencia adicional solo por eso (la división no es tan difícil, después de todo), pero si está utilizando Commons Lang de todos modos, están los DurationFormatUtils .

Ejemplo de uso (adaptado de aquí ):

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

Ejemplo:

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

//Output: 2s

Nota : Para obtener millis de dos objetos LocalDateTime, puede usar:

long age = ChronoUnit.MILLIS.between(initTime, LocalDateTime.now())
Thilo
fuente
1
Genial, solo me preguntaba si había una biblioteca robusta que incluyera este tipo de cosas.
Lajcik
Como un enlace generalmente no es muy útil, agregué un ejemplo sobre cómo se puede usar.
lepe
26

Divide a mano o usa la 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)));

Editar por Bombe : Se ha demostrado en los comentarios que este enfoque solo funciona para duraciones más pequeñas (es decir, menos de un día).

cadrian
fuente
Guau. Ese es un truco malvado que depende de la zona horaria. Se romperá sin piedad cuando tenga un desplazamiento de zona horaria que no sea un múltiplo de 60 minutos (y tenemos un par de esas zonas de tiempo molestas de 30 minutos en el mundo).
Bombe
Además, se romperá tan mal tan pronto como incluya las horas en la cadena de formato y no esté en GMT + 0, por las mismas razones.
Bombe
¿Hacemos? De Verdad? ¿Dónde? Sin dudarlo, nunca antes había oído hablar de él: algunos nuevos obstáculos a tener en cuenta ;-)
Treb
Si. Verifique “Lista de zonas horarias” en Wikipedia, por ejemplo, Nepal está en GMT + 05: 45.
Bombe
2
cadrian, ahora solo funcionará por menos de un día. El número de horas siempre estará entre 0 y 23, inclusive.
Bombe
21

Solo para agregar más información si desea formatear como: HH: mm: ss

0 <= HH <= infinito

0 <= mm <60

0 <= ss <60

utilizar este:

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

Acabo de tener este problema ahora y descubrí esto

fredcrs
fuente
1
La mejor respuesta aquí. ¿Por qué todos quieren hacer las cosas tan complicadas? Esto es matemática simple, amigos.
Lambart
11

Creo que la mejor manera es:

String.format("%d min, %d sec", 
    TimeUnit.MILLISECONDS.toSeconds(length)/60,
    TimeUnit.MILLISECONDS.toSeconds(length) % 60 );
Xtera
fuente
por minutos puedes usar TimeUnit.MILLISECONDS.toMinutes (length)
EminenT
11

La solución más corta:

Aquí es probablemente el más corto que también se ocupa de las zonas horarias.

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

Qué salidas, por ejemplo:

00:18:32

Explicación:

%tTes la hora formateada para el reloj de 24 horas como %tH:%tM:%tS.

%tTtambién acepta largos como entrada, por lo que no es necesario crear un Date. printf()simplemente imprimirá la hora especificada en milisegundos, pero en la zona horaria actual, por lo tanto, tenemos que restar el desplazamiento bruto de la zona horaria actual para que 0 milisegundos sean 0 horas y no el valor de compensación horaria de la zona horaria actual.

Nota # 1: Si necesita el resultado como a String, puede obtenerlo así:

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

Nota # 2: Esto solo da el resultado correcto si millises menos de un día porque la parte del día no está incluida en la salida.

icza
fuente
Este es un gran atajo, pero cuando lo uso no obtengo los resultados esperados. Así que tengo: long millis = 8398;y cuando paso eso a String.format("%tT", millis)mi salida es 19:00:08. ¿De dónde vienen los 19?
Nelda.techspiress
1
@ Nelda.techspiress Ese es el desplazamiento de su zona horaria. Tienes que restarle TimeZone.getDefault().getRawOffset(), exactamente como está escrito en la respuesta:String.format("%tT", millis-TimeZone.getDefault().getRawOffset())
icza
Eso lo cuidó. Gracias por la aclaración.
Nelda.techspiress
8

Joda-Time

Usando 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
fuente
1
No hay necesidad de eso PeriodFormaten la última línea. Simplemente llame Period::toStringpara obtener una cadena de duración ISO 8601 de forma predeterminada.
Basil Bourque
8

Revisando la contribución @ brent-nash, podríamos usar la función de módulo en lugar de sustracciones y usar el método String.format para la cadena de resultado:

  /**
   * 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
fuente
6

para Android debajo de 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
fuente
5

Para tiempos pequeños, menos de una hora, prefiero:

long millis = ...

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

para intervalos más largos:

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);
}
usuario85421
fuente
Esa es una sugerencia preciosa, ¡existen muchas posibilidades de fecha y hora con Java Formatter API ( docs.oracle.com/javase/8/docs/api/java/util/Formatter.html )! También puede obtener el resultado de la condición else con: System.out.printf ("% 1 $ tH:% 1 $ tM:% 1 $ tS% n", millis); o incluso System.out.printf ("% 1 $ tT% n", millis);
Jose Tepedino
@JoseTepedino pero ¿sabes que %tH solo se muestra de 0 a 23 horas? Eso significa que, por ejemplo, 24 horas se mostrarán como 00, 25 horas como 01... lo mismo válido para %tT- los días se descartarán en silencio. Claro, también podría mostrar días, pero eso sería una exageración para el problema que tuve cuando escribí esto (en 2011) [:-)
user85421
Ya veo ... eso realmente solo funcionaría por menos de un día (24h). Gracias.
Jose Tepedino
5

Mi simple cálculo:

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

Feliz codificación :)

Shohan Ahmed Sijan
fuente
Supongo que long es más apropiado para esta función, ya que System.currentTimeMillis () devuelve un valor largo.
Aprodan
Esto no es correcto, ¿ha verificado la salida?
Jorgesys
4

Aquí hay una respuesta basada en la respuesta de Brent Nash, ¡espero que ayude!

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
fuente
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
fuente
3
La fórmula en la línea 6 es incorrecta. diff=diff-(hours*60*1000);debería ser diff=diff-(hours*60*60*1000);. Intenté editarlo, pero la molesta política de edición de StackOverflow dice que no hay suficientes caracteres para una edición.
quux00
4

En primer lugar, System.currentTimeMillis()y Instant.now()no son ideales para el tiempo. Ambos informan la hora del reloj de pared, que la computadora no conoce con precisión, y que puede moverse erráticamente, incluso retroceder si, por ejemplo, el demonio NTP corrige la hora del sistema. Si su sincronización ocurre en una sola máquina, entonces debería usar System.nanoTime () .

En segundo lugar, desde Java 8 en adelante, java.time.Duration es la mejor manera de representar una duración:

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
fuente
3

Si sabe que la diferencia horaria sería inferior a una hora, puede usar el siguiente código:

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

Resultará a: 51:00

Gourav Singla
fuente
3

Esta respuesta es similar a algunas respuestas anteriores. Sin embargo, creo que sería beneficioso porque, a diferencia de otras respuestas, esto eliminará cualquier coma o espacio en blanco adicional y maneja la abreviatura.

/**
 * 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
fuente
3

Hay un problema. Cuando milisegundos es 59999, en realidad es 1 minuto, pero se calculará como 59 segundos y se perderán 999 milisegundos.

Aquí hay una versión modificada basada en respuestas anteriores, que puede resolver esta pérdida:

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
fuente
2

Esto es más fácil en Java 9:

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

Esto produce una cadena como 0 hours, 39 mins, 9 seconds.

Si desea redondear a segundos completos antes de formatear:

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

Para dejar fuera las horas si son 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());
    }

Ahora podemos tener por ejemplo 39 mins, 9 seconds.

Para imprimir minutos y segundos con cero a la izquierda para que siempre tengan dos dígitos, simplemente inserte 02en los especificadores de formato relevantes, de esta manera:

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

Ahora podemos tener por ejemplo 0 hours, 39 mins, 09 seconds.

Ole VV
fuente
¿Algún formato para eliminar horas / minutos / segundos cuando un número anterior es 0? Quiero decir que se puede lograr con la condición if else, pero ¿qué pasa con la existencia de dicho formato de cadena o algo similar, hay alguno?
Farid
1
No, lo siento, @FARID, necesitas if... elseallí.
Ole VV
1

para las cadenas correctas ("1 hora, 3 segundos", "3 minutos" pero no "0 horas, 0 minutos, 3 segundos") escribo este código:

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";
Juan
fuente
1

Modifiqué la respuesta de @MyKuLLSKI y agregué soporte de plurlización. Saqué segundos porque no los necesitaba, aunque siéntase libre de volver a agregarlo si lo necesita.

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" : "");
}
corriente de bits
fuente
int intervalMins vs long millis
Kiquenet
1

He cubierto esto en otra respuesta pero puedes hacer:

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 salida es algo así Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, con las unidades ordenadas.

Depende de usted descubrir cómo internacionalizar estos datos de acuerdo con la configuración regional de destino.

Sebastien Lorber
fuente
1

Use java.util.concurrent.TimeUnit y use este método 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; 
}

Por ejemplo:

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
fuente