Como converter milissegundos para "X mins, x segundos" em Java?

573

Quero registrar o tempo System.currentTimeMillis()em que um usuário inicia algo no meu programa. Quando ele terminar, subtrairei a corrente System.currentTimeMillis()da startvariável e quero mostrar o tempo decorrido usando um formato legível por humanos, como "XX horas, XX minutos, XX segundos" ou mesmo "XX minutos, XX segundos", porque provavelmente não levará alguém por uma hora.

Qual é a melhor forma de fazer isso?

Click Voto a favor
fonte
5
Se eles levarem mais de uma hora, você ainda poderá imprimir algo como; 90 minutos, 53 segundos.
31540 Peter Lawrey
1
a minha resposta vem 6 anos atrasado, mas eu acho que é mais genérico do que os aceitos: stackoverflow.com/a/35082080/82609
Sebastien Lorber
1
confira exemplo simples para converter milissegundos em dias, horas, minutos, segundos em Java
sumit kumar pradhan

Respostas:

1229

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

Nota: TimeUnitfaz parte da especificação Java 1.5, mas toMinutesfoi adicionado a partir do Java 1.6.

Para adicionar um zero inicial para os valores de 0 a 9, faça o seguinte:

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

Se TimeUnitou toMinutesnão é suportado (como no Android antes da API versão 9), use as seguintes equações:

int seconds = (int) (milliseconds / 1000) % 60 ;
int minutes = (int) ((milliseconds / (1000*60)) % 60);
int hours   = (int) ((milliseconds / (1000*60*60)) % 24);
//etc...
siddhadev
fonte
5
int meses = (int) ((flutuante) dias / 30.4368499f); int anos = (int) ((flutuante) dias / 365.242199f);
Nathan Schwermann
7
Eu sugiro usar o mod 60 em vez de subtrair os minutos, parece mais limpo. No entanto, é preciso saber que 1 min = 60 segundos para fazer isso ... =)
Per Alexandersson
2
@AndreasDietrich SimpleDateFormat não funciona para diferenças de horário, pois apenas retorna a data da época!
Muhammad Babar 23/10
5
int hours = (int) ((milliseconds / (1000*60*60)) % 24)isso não funciona! em vez disso, deveria ser assimint hours = (int) (milliseconds / (1000*60*60)) ;
Muhammad Babar
5
Se alguém quer um formato para arquivos de vídeo ( h: mm: ss ):String.format("%01d:%02d:%02d", hours, minutes, seconds);
Kazy
124

Com base na resposta de @ siddhadev, escrevi uma função que converte milissegundos em uma string formatada:

   /**
     * 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 escreve código
fonte
2
Você deve fazer uma verificação lá para único / múltiplo, a fim de evitar esse tipo de situação:1 Days 1 Hours 1 Minutes 1 Seconds
Daniel
7
Poderíamos usar a função módulo em vez de subtração: 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; e também método String.format:return String.format("%d Days %d Hours %d Minutes %d Seconds %d Milliseconds", days, hours, minutes, seconds, milliseconds);
José Tepedino
78
long time = 1536259;

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

Impressões:

25: 36: 259

Damien
fonte
1
Eu gosto da abordagem acima, o melhor, se por nada mais a sua simplicidade! Como estamos lidando com tempos e durações, normalmente uso o Joda. Um exemplo, se você tiver dois DateTimes, inicie e termine respectivamente:Duration dur = new Duration(start, end); long millis = dur.getMillis();
TechTrip 2/12/12 /
1
Eu deveria ter notado duas maneiras de usar os formatadores Joda. Primeira variação no seu tema: DateTimeFormat.forPattern("mm:ss:SSS").print(new DateTime(time)); ou converta a Duração em um Período que pode ser impresso automaticamente usando um Joda PeriodFormatter. A conversão pode ter uma perda de precisão se não for a cronologia ISO. Suponha uma Duração representada pela variável duration. Period period = duration.toPeriod().normalizedStandard(PeriodType.time()); PeriodFormat.getDefault().print(period)) A produção é impressionante: 1 segundo e 581 milissegundos, respondendo à principal pergunta acima.
TechTrip
2
Um pouco tarde aqui :) Mas você não precisaria colocar simpleDateFormat.setTimezone (TimeZone.getTimeZone ("GMT")) aqui, a menos que esse seja o seu fuso horário real?
Olle Söderström 19/04
@ OlleSöderström De fato, há um problema com o fuso horário aqui. Mas defini-lo como GMT ou UTC faz com que a parte da hora seja 12 em vez de 0 para todas as durações inferiores a 1 hora.
Episodex
2
O fuso horário não é o único problema aqui ... esta resposta é enganosa e pode confundir seriamente os iniciantes em Java. Mesmo ignorando os colchetes externos redundantes, o OP perguntou como apresentar uma duração (uma diferença entre dois pontos no tempo, medida em ms). Chamar essa duração de "tempo" e tratá-la como um deslocamento desde 1 de janeiro de 1970 apenas por uma questão de formatar seus componentes menores é ... imo errado. Além disso, a mesma abordagem já havia sido sugerida três anos antes por esta resposta (consulte os comentários para obter mais detalhes sobre problemas no fuso horário).
Amos M. Carpenter
36

Uhm ... quantos milissegundos existem em um segundo? E em um minuto? Divisão não é tão difícil.

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

Continue assim por horas, dias, semanas, meses, ano, décadas, o que for.

Bombe
fonte
2
Na verdade, fazer isso por mais de uma hora não é uma boa ideia, pois os resultados podem ser errados / pouco intuitivos quando o horário de verão (dias de 23 ou 24 horas) ou anos bissextos estão envolvidos. Se eu ler "X acontecerá em 1 ano / mês", espero que seja a mesma data e hora.
227 Michael Borgwardt
5
System.currentTimeMillis () é imune ao horário de verão, portanto, isso não será confundido por horas adicionais ou ausentes. Se você precisar mostrar a diferença entre duas datas específicas, é melhor criar objetos Date com o tempo determinado e mostrar a diferença entre essas duas datas.
Bombe
1
Além de semanas, é indefinido, pois a duração do mês é variável. Então, de fato, você precisa calcular em relação a uma referência de tempo específica.
PhiLho
31

Usando o pacote java.time no Java 8:

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

A saída está no formato ISO 8601 Duration : PT1M3.553S(1 minuto e 3.553 segundos).

Vitalii Fedorenko
fonte
1
(ANDROID) Requer API nível 26
Alguém em algum lugar
1
@SomeoneSomewhere Para Android no nível da API 26, use o backport, consulte Como usar o ThreeTenABP no Android Project .
Ole VV
1
Isso é incrível :) obrigado pelo aviso!
Alguém em algum lugar
27

Eu não extrairia a dependência extra apenas para isso (afinal, a divisão não é tão difícil), mas se você estiver usando o Commons Lang de qualquer maneira, há o DurationFormatUtils .

Exemplo de uso (adaptado daqui ):

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

Exemplo:

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

//Output: 2s

Nota : Para obter millis de dois objetos LocalDateTime, você pode usar:

long age = ChronoUnit.MILLIS.between(initTime, LocalDateTime.now())
Thilo
fonte
1
Ótimo, eu estava me perguntando se havia uma biblioteca robusta que incluísse esse tipo de coisa.
Lajcik 18/01/11
Como um link geralmente não é muito útil, adicionei um exemplo de como ele pode ser usado.
quer
26

Divisões manuais, ou use a 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 : Foi demonstrado nos comentários que essa abordagem funciona apenas por períodos menores (ou seja, menos de um dia).

Cadrian
fonte
Uau. Esse é um hack maligno e dependente do fuso horário. Ele quebrará sem piedade quando você tiver um deslocamento de fuso horário que não seja múltiplo de 60 minutos (e temos alguns desses fusos horários de deslocamento de 30 minutos no mundo).
9609 Bombe
Além disso, ele será quebrado assim que você incluir as horas na string de formato e não estiver no GMT + 0, pelos mesmos motivos.
9609 Bombe
Nós fazemos? Mesmo? Onde? Não duvidando de você, nunca ouvi falar disso antes - uma nova armadilha de considerar ;-)
Treb
Sim. Verifique “Lista de fusos horários” na Wikipedia, por exemplo, o Nepal está em GMT + 05: 45.
9609 Bombe
2
agora, ele só funcionará por durações inferiores a um dia. O número de horas sempre estará entre 0 e 23, inclusive.
Bombe
21

Apenas para adicionar mais informações, se você deseja formatar como: HH: mm: ss

0 <= HH <= infinito

0 <= mm <60

0 <= ss <60

usa isto:

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

Eu só tinha esse problema agora e descobri isso

fredcrs
fonte
1
Melhor resposta aqui. Por que todo mundo quer tornar as coisas tão complicadas? Isso é matemática simples, pessoal.
Lambart
11

Eu acho que a melhor maneira é:

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

Solução mais curta:

Aqui está provavelmente o mais curto, que também lida com fusos horários.

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

Quais saídas, por exemplo:

00:18:32

Explicação:

%tTé a hora formatada para o relógio de 24 horas como %tH:%tM:%tS.

%tTtambém aceita longs como entrada, portanto, não há necessidade de criar um Date. printf()simplesmente imprimirá a hora especificada em milissegundos, mas no fuso horário atual, portanto, temos que subtrair o deslocamento bruto do fuso horário atual para que 0 milissegundos sejam 0 horas e não o valor do deslocamento de hora do fuso horário atual.

Nota 1: se você precisar do resultado como a String, poderá obtê-lo assim:

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

Nota 2: Isso só fornece resultado correto se millisfor menor que um dia, porque a parte do dia não está incluída na saída.

icza
fonte
Esse é um atalho muito bom, mas quando o uso, não obtenho os resultados esperados. Então eu tenho: long millis = 8398;e quando passo isso para a String.format("%tT", millis)minha saída é 19:00:08. De onde vêm os 19?
Nelda.techspiress 15/08/19
1
@ Nelda.techspiress Esse é o deslocamento do seu fuso horário. Você deve subtraí TimeZone.getDefault().getRawOffset()-lo, exatamente como está escrito na resposta:String.format("%tT", millis-TimeZone.getDefault().getRawOffset())
icza 15/08
que cuidou disso. Obrigado por esclarecer.
Nelda.techspiress 15/08/19
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
fonte
1
Não há necessidade disso PeriodFormatna última linha. Basta ligar Period::toStringpara obter uma sequência de duração ISO 8601 por padrão.
Basil Bourque
8

Revisitando a contribuição @ brent-nash, poderíamos usar a função de módulo em vez de subtrações e usar o método String.format para a sequência de resultados:

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

para Android abaixo da 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
fonte
5

Por tempos pequenos, menos de uma hora, prefiro:

long millis = ...

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

para intervalos mais longos:

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
fonte
Essa é uma dica preciosa, existem muitas possibilidades para data e hora com a API Java Formatter ( docs.oracle.com/javase/8/docs/api/java/util/Formatter.html )! Você também pode obter o resultado da condição else com: System.out.printf ("% 1 $ tH:% 1 $ tM:% 1 $ tS% n", milis); ou até System.out.printf ("% 1 $ tT% n", milis);
Jose Tepedino
@JoseTepedino, mas você sabe que mostra %tH apenas de 0 a 23 horas? Isso significa que, por exemplo, 24 horas seriam exibidas como 00, 25 horas como01 ... mesmas válidas por %tT- dias serão descartadas silenciosamente. Claro, também pode ter dias exibida, mas isso seria um exagero para o problema que eu tive quando eu escrevi isso (de volta em 2011) [:-)
user85421
Entendo ... isso só funcionaria por menos de um dia (24h). Obrigado.
Jose Tepedino
5

Meu cálculo simples:

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 codificação :)

Shohan Ahmed Sijan
fonte
Suponho que long seja mais apropriado para essa função, pois System.currentTimeMillis () retorna um valor longo.
Aprodan
Isso não está correto, você verificou a saída?
Jorgesys
4

Aqui está uma resposta baseada na resposta de Brent Nash, Espero que ajude!

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
fonte
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
fonte
3
A fórmula na linha 6 está errada. diff=diff-(hours*60*1000);deveria ser diff=diff-(hours*60*60*1000);. Tentei editá-lo, mas a política de edição irritante do StackOverflow diz que não há caracteres suficientes para uma edição.
quux00
4

Em primeiro lugar, System.currentTimeMillis()e Instant.now()não são ideais para o tempo. Ambos relatam a hora do relógio de parede, que o computador não sabe com precisão e que pode se mover erraticamente, incluindo retroceder se, por exemplo, o daemon NTP corrigir a hora do sistema. Se o tempo ocorrer em uma única máquina, você deverá usar System.nanoTime () .

Em segundo lugar, do Java 8 em diante, java.time.Duration é a melhor maneira de representar uma duração:

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

Se você souber que a diferença horária seria menor que uma hora, poderá usar o seguinte 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)));

O resultado será: 51:00

Gourav Singla
fonte
3

Esta resposta é semelhante a algumas respostas acima. No entanto, acho que seria benéfico porque, diferentemente de outras respostas, isso removerá qualquer vírgula ou espaço em branco extra e manipulará a abreviação.

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

Há um problema. Quando milissegundos é 59999, na verdade é 1 minuto, mas será calculado em 59 segundos e 999 milissegundos são perdidos.

Aqui está uma versão modificada com base nas respostas anteriores, que podem resolver essa perda:

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

Isso é mais fácil no Java 9:

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

Isso produz uma string como 0 hours, 39 mins, 9 seconds .

Se você deseja arredondar para segundos inteiros antes de formatar:

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

Para deixar de fora as horas, se forem 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());
    }

Agora podemos ter, por exemplo 39 mins, 9 seconds.

Para imprimir minutos e segundos com zero à esquerda para torná-los sempre com dois dígitos, basta inserir 02nos especificadores de formato relevantes, assim:

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

Agora podemos ter, por exemplo 0 hours, 39 mins, 09 seconds.

Ole VV
fonte
Alguma formatação para remover horas / minutos / segundos quando um número anterior é 0? Quero dizer, é possível com a condição if else, mas e quanto à existência dessa formatação de String ou algo próximo, existe alguma?
Farid
1
Não, desculpe, @FARID, você precisa if- elseaí.
VV Ole VV
1

para seqüências corretas ("1 hora, 3seg", "3 min", mas não "0 horas, 0 min, 3 seg"), escrevo 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";
John
fonte
1

Modifiquei a resposta de @MyKuLLSKI e adicionei suporte à plurlização. Demorei alguns segundos porque não precisava deles, mas fique à vontade para adicioná-lo novamente, se precisar.

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

Eu cobri isso em outra resposta, mas você pode fazer:

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

A saída é algo como Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0} , com as unidades encomendadas.

Cabe a você descobrir como internacionalizar esses dados de acordo com o local de destino.

Sebastien Lorber
fonte
1

Use java.util.concurrent.TimeUnit e use este método simples:

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 exemplo:

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
fonte