Convert seconds to days, hours, minutes and seconds

Viewed 63408

I have a Javascript timing event with an infinite loop with a stop button.

It will display numbers when start button is click.Now I want this numbers converted to something like 4 hours, 3 minutes , 50 seconds

var c = 0;
var t;
var timer_is_on = 0;

function timedCount() {
  document.getElementById('txt').value = c;
  c = c + 1;
  t = setTimeout(function() {
    timedCount()
  }, 1000);
}

function doTimer() {
  if (!timer_is_on) {
    timer_is_on = 1;
    timedCount();
  }
}

function stopCount() {
  clearTimeout(t);
  timer_is_on = 0;

}

$(".start").on("click", function() {
  //var start = $.now();
  //alert(start);
  //console.log(start);
  doTimer();
  $(".end").show();
  $(".hide_div").show();
});
$(".end").on("click", function() {
  stopCount();
});
.hide_div {
  display: none;
}

.end {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p class="start">Start</p>
<p class="end">End</p>
<p class="hide_div">
  <input type="text" id="txt" />//display numbers eg 12345
</p>

How to convert numbers like 123456 to 1 day, 4 hours, 40 min, 45 seconds?

12 Answers

I suggest doing this way!:

function secondsToDhms(seconds) {
seconds = Number(seconds);
var d = Math.floor(seconds / (3600*24));
var h = Math.floor(seconds % (3600*24) / 3600);
var m = Math.floor(seconds % 3600 / 60);
var s = Math.floor(seconds % 60);

var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : "";
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
return dDisplay + hDisplay + mDisplay + sDisplay;
}
function countdown(s) {

  const d = Math.floor(s / (3600 * 24));

  s  -= d * 3600 * 24;

  const h = Math.floor(s / 3600);

  s  -= h * 3600;

  const m = Math.floor(s / 60);

  s  -= m * 60;

  const tmp = [];

  (d) && tmp.push(d + 'd');

  (d || h) && tmp.push(h + 'h');

  (d || h || m) && tmp.push(m + 'm');

  tmp.push(s + 's');

  return tmp.join(' ');
}

// countdown(3546544) -> 41d 1h 9m 4s
// countdown(436654) -> 5d 1h 17m 34s
// countdown(3601) -> 1h 0m 1s
// countdown(121) -> 2m 1s

My solution with map() and reduce():

const intervalToLevels = (interval, levels) => {
  const cbFun = (d, c) => {
    let bb = d[1] % c[0],
      aa = (d[1] - bb) / c[0];
    aa = aa > 0 ? aa + c[1] : '';

    return [d[0] + aa, bb];
  };

  let rslt = levels.scale.map((d, i, a) => a.slice(i).reduce((d, c) => d * c))
    .map((d, i) => ([d, levels.units[i]]))
    .reduce(cbFun, ['', interval]);
  return rslt[0];
};

const TimeLevels = {
  scale: [24, 60, 60, 1],
  units: ['d ', 'h ', 'm ', 's ']
};
const secondsToString = interval => intervalToLevels(interval, TimeLevels);

If you call secondsToString(123456), you can get "1d 10h 17m 36s "

Here is my solution, a simple function that will round to the nearest second!

var returnElapsedTime = function(epoch) {
  //We are assuming that the epoch is in seconds
  var hours = epoch / 3600,
      minutes = (hours % 1) * 60,
      seconds = (minutes % 1) * 60;
  return Math.floor(hours) + " hours, " + Math.floor(minutes) + " minutes, " + Math.round(seconds) + " seconds";
}

Came up with my own variation to some of the solutions suggested in this thread.

if (!Number.prototype.secondsToDHM) {
    Number.prototype.secondsToDHM = function() {
        const secsPerDay = 86400;
        const secsPerHour = 3600;
        const secsPerMinute = 60;

        var seconds = Math.abs(this);
        var minus   = (this < 0) ? '-' : '';
        
        var days    = Math.floor(seconds / secsPerDay);
        seconds     = (seconds % secsPerDay);
        var hours   = Math.floor(seconds / secsPerHour);
        seconds     = (seconds % secsPerHour);
        var minutes = Math.floor(seconds / secsPerMinute);
        seconds     = (seconds % secsPerMinute);

        var sDays    = new String(days).padStart(1, '0');
        var sHours   = new String(hours).padStart(2, '0');
        var sMinutes = new String(minutes).padStart(2, '0');

        return `${minus}${sDays}D ${sHours}:${sMinutes}`;
    }
}

var a = new Number(50000).secondsToDHM();
var b = new Number(100000).secondsToDHM();
var c = new Number(200000).secondsToDHM();
var d = new Number(400000).secondsToDHM();

console.log(a);
console.log(b);
console.log(c);
console.log(d);

This answer builds upon on Andris' approach to this question, but it doesn't have trailing commas if lesser units are not present.

It also borrows from this answer dealing with joining array values only if truthy:

https://stackoverflow.com/a/19903063

I'm not a javascript god and it's probably horribly over-engineered, but hopefully readable and correct!

function sformat(s) {

    // create array of day, hour, minute and second values
    var fm = [
        Math.floor(s / (3600 * 24)),
        Math.floor(s % (3600 * 24) / 3600),
        Math.floor(s % 3600 / 60),
        Math.floor(s % 60)
    ];

    // map over array
    return $.map(fm, function(v, i) {

        // if a truthy value
        if (Boolean(v)) {

            // add the relevant value suffix
            if (i === 0) {
                v = plural(v, "day");
            } else if (i === 1) {
                v = plural(v, "hour");
            } else if (i === 2) {
                v = plural(v, "minute");
            } else if (i === 3) {
                v = plural(v, "second");
            }

            return v;
        }

    }).join(', ');

}

function plural(value, unit) {

    if (value === 1) {
        return value + " " + unit;
    } else if (value > 1) {
        return value + " " + unit + "s";
    }

}


console.log(sformat(60)); // 1 minute
console.log(sformat(3600)); // 1 hour
console.log(sformat(86400)); // 1 day
console.log(sformat(8991)); // 2 hours, 29 minutes, 51 seconds

If you needed to convey the duration more 'casually' in words, you could also do something like:

var remaining_duration = sformat(117);
// if a value is returned, add some prefix and suffix 
if (remaining_duration !== "") {
    remaining_duration = "about " + remaining_duration + " left";
}
$(".remaining_duration").text(remaining_duration);

// returns 'about 1 minute, 57 seconds left'

I further tweaked the code by Svetoslav as follows:

function convertSecondsToReadableString(seconds) {
  seconds = seconds || 0;
  seconds = Number(seconds);
  seconds = Math.abs(seconds);

  const d = Math.floor(seconds / (3600 * 24));
  const h = Math.floor(seconds % (3600 * 24) / 3600);
  const m = Math.floor(seconds % 3600 / 60);
  const s = Math.floor(seconds % 60);
  const parts = [];

  if (d > 0) {
    parts.push(d + ' day' + (d > 1 ? 's' : ''));
  }

  if (h > 0) {
    parts.push(h + ' hour' + (h > 1 ? 's' : ''));
  }

  if (m > 0) {
    parts.push(m + ' minute' + (m > 1 ? 's' : ''));
  }

  if (s > 0) {
    parts.push(s + ' second' + (s > 1 ? 's' : ''));
  }

  return parts.join(', ');
}

Short answer:

var s = (Math.floor(123456/86400) + ":" + (new Date(123456 * 1000)).toISOString().substr(11, 8)).split(":");
console.log(`${s[0]} days, ${s[1]} hours, ${s[2]} minutes, ${s[3]} seconds` )

Edit:

Let me break it down in parts :

Math.floor(123456/86400)

86400 is the the total seconds in a day (60 seconds * 60 minutes * 24 hours). Dividing the inputted seconds by this value gives us number of days. We just need the whole part so we use Math.floor because the fractional piece is handled by this part:

(new Date(123456 * 1000)).toISOString().substr(11, 8)

the explanation can be found here:

Convert seconds to HH-MM-SS with JavaScript?

It just outputs hh:mm:ss, no days. So the first part and this part is a perfect combination

We concatenate using a colon (:) as a separator. The string looks like this:

'1:10:17:36'

We split it into an array with .split(":");. Then finally, we format the elements of the array for the desired output.

I've tweaked the code that Andris posted https://stackoverflow.com/users/3564943/andris

            // https://stackoverflow.com/questions/36098913/convert-seconds-to-days-hours-minutes-and-seconds
        function app_ste_36098913_countdown_seconds_to_hr(seconds) {
            seconds = seconds || 0;
            seconds = Number(seconds);
            seconds = Math.abs(seconds);

            var d = Math.floor(seconds / (3600*24));
            var h = Math.floor(seconds % (3600*24) / 3600);
            var m = Math.floor(seconds % 3600 / 60);
            var s = Math.floor(seconds % 60);
            var parts = new Array();

            if (d > 0) {
                var dDisplay = d > 0 ? d + ' ' + (d == 1 ? "day" : "days") : "";
                parts.push(dDisplay);
            }

            if (h > 0) {
                var hDisplay = h > 0 ? h + ' ' + (h == 1 ? "hour" : "hours") : "";
                parts.push(hDisplay)
            }

            if (m > 0) {
                var mDisplay = m > 0 ? m + ' ' + (m == 1 ? "minute" : "minutes") : "";
                parts.push(mDisplay)
            }

            if (s > 0) {
                var sDisplay = s > 0 ? s + ' ' + (s == 1 ? "second" : "seconds") : "";
                parts.push(sDisplay)
            }

            return parts.join(', ', parts);
        }

This is my take at the question, even if it is an old topic.

You can use a loop to compute everything for you :

function time_remaining(date1, date2) {
  let seconds = (date2 - date1) / 1000

  let units = ["years", "days", "h", "min", "s"]
  let limit_units = [365, 24, 60, 60, 1]
  const reducer = (accumulator, curr) => accumulator * curr;

  let time = []
  for (let i = 0; i < units.length; i++) {
    let divisor = limit_units.slice(i).reduce(reducer)
    let value = Math.floor(seconds / divisor)
    seconds = seconds - value * divisor

    time.push(value)
  }

  return clean_time(time, units)
}

// at this point, you have your answer. However,
// we can improve the result by removing all none
// significative null units (i.e, if your countdown is
// only about hours, minutes and seconds, it is not
// going to include years and days.)

function clean_time(time, units) {
  time = time.reverse()

  while (time[time.length - 1] == 0) {
    time.pop()
  }

  return [time.reverse(), units.slice(-time.length)]
}

let date1 = Date.parse("2023-07-09T17:50:33")
console.log(time_remaining(Date.now(), date1))

Related