Como converter milissegundos em forma legível por humanos?

118

Preciso converter uma quantidade arbitrária de milissegundos em dias, horas, minutos e segundos.

Por exemplo: 10 dias, 5 horas, 13 minutos, 1 segundo.

FlySwat
fonte
"A linguagem que estou usando não tem isso integrado, caso contrário, eu usaria." Acho isso difícil de entender. Que lingua? Qual sistema operacional?
S.Lott,
ActionScript, qualquer sistema operacional, tem suporte péssimo de data / hora
FlySwat
3
Não conheço nenhuma língua que tenha o que ele está pedindo, nem vejo razão para que tenha. Algumas matemáticas de divisão / módulo muito simples fornecem a resposta muito bem.
Kip,
1
Nem todos os anos têm o mesmo número de dias, então você deve indicar qual foi o período. Ou talvez você queira apenas em anos 'padrão' (365.algo)?
Milan Babuškov,
@Kip: Entendi - interpretou mal a pergunta - estava pensando nos carimbos de data / hora do SO em milissegundos. Não delta vezes ou intervalos. Tentação de editar a pergunta ...
S.Lott

Respostas:

226

Bem, já que ninguém mais avançou, vou escrever o código fácil para fazer isso:

x = ms / 1000
seconds = x % 60
x /= 60
minutes = x % 60
x /= 60
hours = x % 24
x /= 24
days = x

Estou feliz que você parou por dias e não perguntou por meses. :)

Observe que no exemplo acima, é assumido que /representa a divisão inteira truncada. Se você usar este código em uma linguagem onde /representa a divisão de ponto flutuante, você precisará truncar manualmente os resultados da divisão conforme necessário.

Greg Hewgill
fonte
2
Só usei isso em uma função de flash. obrigado! (votos positivos para simplicidade)
Makram Saleh
2
Não funciona corretamente. Deve usar parseInt ao usar o divisor, caso contrário, você verá valores de float longos. Veja minha resposta abaixo para uma solução mais abrangente.
Rajiv
17
@Greg Hewgill Estou feliz que você parou por dias e não perguntou por meses. :) haha :)
moshfiqur
58

Seja A a quantidade de milissegundos. Então você tem:

seconds=(A/1000)%60
minutes=(A/(1000*60))%60
hours=(A/(1000*60*60))%24

e assim por diante ( %é o operador de módulo).

Espero que isto ajude.

Gabriele D'Antona
fonte
@sabbibJAVA 24 deve ter funcionado. Em que idioma você está? Se /fizer divisão de ponto flutuante, você precisará truncar o valor. É assumido em outras respostas que /está realizando divisão inteira.
Brian J de
24

Ambas as soluções abaixo usam javascript (eu não tinha ideia de que a solução era independente de linguagem!). Ambas as soluções precisarão ser estendidas se capturar as durações > 1 month.

Solução 1: usar o objeto Date

var date = new Date(536643021);
var str = '';
str += date.getUTCDate()-1 + " days, ";
str += date.getUTCHours() + " hours, ";
str += date.getUTCMinutes() + " minutes, ";
str += date.getUTCSeconds() + " seconds, ";
str += date.getUTCMilliseconds() + " millis";
console.log(str);

Dá:

"6 days, 5 hours, 4 minutes, 3 seconds, 21 millis"

As bibliotecas são úteis, mas por que usar uma biblioteca se você pode reinventar a roda! :)

Solução 2: escreva seu próprio analisador

var getDuration = function(millis){
    var dur = {};
    var units = [
        {label:"millis",    mod:1000},
        {label:"seconds",   mod:60},
        {label:"minutes",   mod:60},
        {label:"hours",     mod:24},
        {label:"days",      mod:31}
    ];
    // calculate the individual unit values...
    units.forEach(function(u){
        millis = (millis - (dur[u.label] = (millis % u.mod))) / u.mod;
    });
    // convert object to a string representation...
    var nonZero = function(u){ return dur[u.label]; };
    dur.toString = function(){
        return units
            .reverse()
            .filter(nonZero)
            .map(function(u){
                return dur[u.label] + " " + (dur[u.label]==1?u.label.slice(0,-1):u.label);
            })
            .join(', ');
    };
    return dur;
};

Cria um objeto de "duração", com todos os campos de que você precisa. Formatar um carimbo de data / hora se torna simples ...

console.log(getDuration(536643021).toString());

Dá:

"6 days, 5 hours, 4 minutes, 3 seconds, 21 millis"
Nick Grealy
fonte
Altere essa linha para ficar no singular e no plural return dur[u.label] + " " + (dur[u.label]==1?u.label.slice(0,-1):u.label);
Phillip Kamikaze
1
@PhillipKamikaze Obrigado Phillip! Eu incorporei sua sugestão.
Nick Grealy
Você provavelmente não quer mostrar segmentos com valores zero, então o seguinte filtro pode ser adicionado ... var nonZero = function(u){ return !u.startsWith("0"); }; // convert object to a string representation... dur.toString = function(){ return units.reverse().map(function(u){ return dur[u.label] + " " + (dur[u.label]==1?u.label.slice(0,-1):u.label); }).filter(nonZero).join(', '); };
Ruslan Ulanov
1
Obrigado @RuslanUlanov! Eu o adicionei ao exemplo (embora com uma ligeira modificação para verificar se o número é "verdadeiro").
Nick Grealy
7

Você deve usar as funções datetime de qualquer linguagem que esteja usando, mas, apenas por diversão, aqui está o código:

int milliseconds = someNumber;

int seconds = milliseconds / 1000;

int minutes = seconds / 60;

seconds %= 60;

int hours = minutes / 60;

minutes %= 60;

int days = hours / 24;

hours %= 24;
albertein
fonte
4

Este é um método que escrevi. Leva um integer milliseconds valuee retorna um human-readable String:

public String convertMS(int ms) {
    int seconds = (int) ((ms / 1000) % 60);
    int minutes = (int) (((ms / 1000) / 60) % 60);
    int hours = (int) ((((ms / 1000) / 60) / 60) % 24);

    String sec, min, hrs;
    if(seconds<10)  sec="0"+seconds;
    else            sec= ""+seconds;
    if(minutes<10)  min="0"+minutes;
    else            min= ""+minutes;
    if(hours<10)    hrs="0"+hours;
    else            hrs= ""+hours;

    if(hours == 0)  return min+":"+sec;
    else    return hrs+":"+min+":"+sec;

}
iTurki
fonte
4
function convertTime(time) {        
    var millis= time % 1000;
    time = parseInt(time/1000);
    var seconds = time % 60;
    time = parseInt(time/60);
    var minutes = time % 60;
    time = parseInt(time/60);
    var hours = time % 24;
    var out = "";
    if(hours && hours > 0) out += hours + " " + ((hours == 1)?"hr":"hrs") + " ";
    if(minutes && minutes > 0) out += minutes + " " + ((minutes == 1)?"min":"mins") + " ";
    if(seconds && seconds > 0) out += seconds + " " + ((seconds == 1)?"sec":"secs") + " ";
    if(millis&& millis> 0) out += millis+ " " + ((millis== 1)?"msec":"msecs") + " ";
    return out.trim();
}
Rajiv
fonte
2

Eu sugeriria usar quaisquer funções / bibliotecas de data / hora que sua linguagem / estrutura de escolha fornecer. Verifique também as funções de formatação de string, pois geralmente fornecem maneiras fáceis de passar data / carimbo de data / hora e gerar um formato de string legível por humanos.

urso-tabaco
fonte
2

Suas escolhas são simples:

  1. Escreva o código para fazer a conversão (ou seja, divida por milliSecondsPerDay para obter dias e use o módulo para dividir por milliSecondsPerHour para obter horas e use o módulo para dividir por miliSecondsPerMinute e divida por 1000 para segundos. MilliSecondsPerMinute = 6000, milliSeconds * milliSecondsPerMinute, milliSecondsPerDay = 24 * milliSecondsPerHour.
  2. Use algum tipo de rotina operacional. Tanto o UNIX quanto o Windows têm estruturas que você pode obter de um valor de tipo Ticks ou segundos.
plinto
fonte
2
Long serverUptimeSeconds = 
    (System.currentTimeMillis() - SINCE_TIME_IN_MILLISECONDS) / 1000;


String serverUptimeText = 
String.format("%d days %d hours %d minutes %d seconds",
serverUptimeSeconds / 86400,
( serverUptimeSeconds % 86400) / 3600 ,
((serverUptimeSeconds % 86400) % 3600 ) / 60,
((serverUptimeSeconds % 86400) % 3600 ) % 60
);
Krolique
fonte
2
Long expireTime = 69l;
Long tempParam = 0l;

Long seconds = math.mod(expireTime, 60);
tempParam = expireTime - seconds;
expireTime = tempParam/60;
Long minutes = math.mod(expireTime, 60);
tempParam = expireTime - minutes;
expireTime = expireTime/60;
Long hours = math.mod(expireTime, 24);
tempParam = expireTime - hours;
expireTime = expireTime/24;
Long days = math.mod(expireTime, 30);

system.debug(days + '.' + hours + ':' + minutes + ':' + seconds);

Isso deve imprimir: 0.0: 1: 9

Asit
fonte
2

Por que simplesmente não faça algo assim:

var ms = 86400;

var segundos = ms / 1000; //86.4

var minutos = segundos / 60; //1.4400000000000002

var horas = minutos / 60; //0.024000000000000004

var dias = horas / 24; //0.0010000000000000002

E lidar com a precisão de float, por exemplo, Number (minutes.toFixed (5)) //1.44

Pavel Blagodov
fonte
2

Em java

public static String formatMs(long millis) {
    long hours = TimeUnit.MILLISECONDS.toHours(millis);
    long mins = TimeUnit.MILLISECONDS.toMinutes(millis);
    long secs = TimeUnit.MILLISECONDS.toSeconds(millis);
    return String.format("%dh %d min, %d sec",
            hours,
            mins - TimeUnit.HOURS.toMinutes(hours),
            secs - TimeUnit.MINUTES.toSeconds(mins)
    );
}

Dá algo assim:

12h 1 min, 34 sec
Camilo Silva
fonte
1

Não posso comentar a primeira resposta à sua pergunta, mas há um pequeno erro. Você deve usar parseInt ou Math.floor para converter números de ponto flutuante em inteiros, i

var days, hours, minutes, seconds, x;
x = ms / 1000;
seconds = Math.floor(x % 60);
x /= 60;
minutes = Math.floor(x % 60);
x /= 60;
hours = Math.floor(x % 24);
x /= 24;
days = Math.floor(x);

Pessoalmente, eu uso CoffeeScript em meus projetos e meu código é assim:

getFormattedTime : (ms)->
        x = ms / 1000
        seconds = Math.floor x % 60
        x /= 60
        minutes = Math.floor x % 60
        x /= 60
        hours = Math.floor x % 24
        x /= 24
        days = Math.floor x
        formattedTime = "#{seconds}s"
        if minutes then formattedTime = "#{minutes}m " + formattedTime
        if hours then formattedTime = "#{hours}h " + formattedTime
        formattedTime 
Rafal Pastuszak
fonte
1

Esta é uma solução. Posteriormente, você pode dividir por ":" e obter os valores da matriz

/**
 * Converts milliseconds to human readeable language separated by ":"
 * Example: 190980000 --> 2:05:3 --> 2days 5hours 3min
 */
function dhm(t){
    var cd = 24 * 60 * 60 * 1000,
        ch = 60 * 60 * 1000,
        d = Math.floor(t / cd),
        h = '0' + Math.floor( (t - d * cd) / ch),
        m = '0' + Math.round( (t - d * cd - h * ch) / 60000);
    return [d, h.substr(-2), m.substr(-2)].join(':');
}

var delay = 190980000;                   
var fullTime = dhm(delay);
console.log(fullTime);
ssamuel68
fonte
1

Aqui está minha solução usando TimeUnit.

ATUALIZAÇÃO: devo ressaltar que isso é escrito em groovy, mas Java é quase idêntico.

def remainingStr = ""

/* Days */
int days = MILLISECONDS.toDays(remainingTime) as int
remainingStr += (days == 1) ? '1 Day : ' : "${days} Days : "
remainingTime -= DAYS.toMillis(days)

/* Hours */
int hours = MILLISECONDS.toHours(remainingTime) as int
remainingStr += (hours == 1) ? '1 Hour : ' : "${hours} Hours : "
remainingTime -= HOURS.toMillis(hours)

/* Minutes */
int minutes = MILLISECONDS.toMinutes(remainingTime) as int
remainingStr += (minutes == 1) ? '1 Minute : ' : "${minutes} Minutes : "
remainingTime -= MINUTES.toMillis(minutes)

/* Seconds */
int seconds = MILLISECONDS.toSeconds(remainingTime) as int
remainingStr += (seconds == 1) ? '1 Second' : "${seconds} Seconds"
dafunker
fonte
1

Uma maneira flexível de fazer isso:
(não feito para a data atual, mas bom o suficiente para durações)

/**
convert duration to a ms/sec/min/hour/day/week array
@param {int}        msTime              : time in milliseconds 
@param {bool}       fillEmpty(optional) : fill array values even when they are 0.
@param {string[]}   suffixes(optional)  : add suffixes to returned values.
                                        values are filled with missings '0'
@return {int[]/string[]} : time values from higher to lower(ms) range.
*/
var msToTimeList=function(msTime,fillEmpty,suffixes){
    suffixes=(suffixes instanceof Array)?suffixes:[];   //suffixes is optional
    var timeSteps=[1000,60,60,24,7];    // time ranges : ms/sec/min/hour/day/week
    timeSteps.push(1000000);    //add very big time at the end to stop cutting
    var result=[];
    for(var i=0;(msTime>0||i<1||fillEmpty)&&i<timeSteps.length;i++){
        var timerange = msTime%timeSteps[i];
        if(typeof(suffixes[i])=="string"){
            timerange+=suffixes[i]; // add suffix (converting )
            // and fill zeros :
            while(  i<timeSteps.length-1 &&
                    timerange.length<((timeSteps[i]-1)+suffixes[i]).length  )
                timerange="0"+timerange;
        }
        result.unshift(timerange);  // stack time range from higher to lower
        msTime = Math.floor(msTime/timeSteps[i]);
    }
    return result;
};

NB: você também pode definir timeSteps como parâmetro se quiser controlar os intervalos de tempo.

como usar (copiar um teste):

var elsapsed = Math.floor(Math.random()*3000000000);

console.log(    "elsapsed (labels) = "+
        msToTimeList(elsapsed,false,["ms","sec","min","h","days","weeks"]).join("/")    );

console.log(    "half hour : "+msToTimeList(elsapsed,true)[3]<30?"first":"second"   );

console.log(    "elsapsed (classic) = "+
        msToTimeList(elsapsed,false,["","","","","",""]).join(" : ")    );
Yorg
fonte
1

Eu sugiro usar http://www.ocpsoft.org/prettytime/ library ..

é muito simples obter o intervalo de tempo em uma forma legível como

PrettyTime p = new PrettyTime(); System.out.println(p.format(new Date()));

vai imprimir como "momentos a partir de agora"

outro exemplo

PrettyTime p = new PrettyTime()); Date d = new Date(System.currentTimeMillis()); d.setHours(d.getHours() - 1); String ago = p.format(d);

então string atrás = "1 hora atrás"

DroidDev
fonte
0

Aqui está um método mais preciso em JAVA, eu implementei essa lógica simples, espero que isso ajude você:

    public String getDuration(String _currentTimemilliSecond)
    {
        long _currentTimeMiles = 1;         
        int x = 0;
        int seconds = 0;
        int minutes = 0;
        int hours = 0;
        int days = 0;
        int month = 0;
        int year = 0;

        try 
        {
            _currentTimeMiles = Long.parseLong(_currentTimemilliSecond);
            /**  x in seconds **/   
            x = (int) (_currentTimeMiles / 1000) ; 
            seconds = x ;

            if(seconds >59)
            {
                minutes = seconds/60 ;

                if(minutes > 59)
                {
                    hours = minutes/60;

                    if(hours > 23)
                    {
                        days = hours/24 ;

                        if(days > 30)
                        {
                            month = days/30;

                            if(month > 11)
                            {
                                year = month/12;

                                Log.d("Year", year);
                                Log.d("Month", month%12);
                                Log.d("Days", days % 30);
                                Log.d("hours ", hours % 24);
                                Log.d("Minutes ", minutes % 60);
                                Log.d("Seconds  ", seconds % 60);   

                                return "Year "+year + " Month "+month%12 +" Days " +days%30 +" hours "+hours%24 +" Minutes "+minutes %60+" Seconds "+seconds%60;
                            }
                            else
                            {
                                Log.d("Month", month);
                                Log.d("Days", days % 30);
                                Log.d("hours ", hours % 24);
                                Log.d("Minutes ", minutes % 60);
                                Log.d("Seconds  ", seconds % 60);   

                                return "Month "+month +" Days " +days%30 +" hours "+hours%24 +" Minutes "+minutes %60+" Seconds "+seconds%60;
                            }

                        }
                        else
                        {
                            Log.d("Days", days );
                            Log.d("hours ", hours % 24);
                            Log.d("Minutes ", minutes % 60);
                            Log.d("Seconds  ", seconds % 60);   

                            return "Days " +days +" hours "+hours%24 +" Minutes "+minutes %60+" Seconds "+seconds%60;
                        }

                    }
                    else
                    {
                        Log.d("hours ", hours);
                        Log.d("Minutes ", minutes % 60);
                        Log.d("Seconds  ", seconds % 60);

                        return "hours "+hours+" Minutes "+minutes %60+" Seconds "+seconds%60;
                    }
                }
                else
                {
                    Log.d("Minutes ", minutes);
                    Log.d("Seconds  ", seconds % 60);

                    return "Minutes "+minutes +" Seconds "+seconds%60;
                }
            }
            else
            {
                Log.d("Seconds ", x);
                return " Seconds "+seconds;
            }
        }
        catch (Exception e) 
        {
            Log.e(getClass().getName().toString(), e.toString());
        }
        return "";
    }

    private Class Log
    {
        public static void d(String tag , int value)
        {
            System.out.println("##### [ Debug ]  ## "+tag +" :: "+value);
        }
    }
AK Joshi
fonte