48

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?

Saeed
  • 5,413
  • 3
  • 26
  • 40
Danielle Rose Mabunga
  • 1,676
  • 4
  • 25
  • 48

12 Answers12

106

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;
}
Andris
  • 3,895
  • 2
  • 24
  • 27
  • cool idea to only include units that are required however the following return trailing commas when smaller unit values are not present: `secondsToDhms(60)` returns `1 minute, `, `secondsToDhms(3600)` returns `1 hour, `and `secondsToDhms(86400)` returns `1 day, `. – user1063287 Jul 06 '19 at 08:16
  • For reference - added an iteration that builds on your answer and addresses some of the issues mentioned in my last comment: https://stackoverflow.com/a/56913131 – user1063287 Jul 06 '19 at 10:14
  • 3
    To remove the trailing commas:- `return (dDisplay + hDisplay + mDisplay + sDisplay).replace(/,\s*$/, "");` – Edamreed Aug 04 '20 at 10:42
44

Use Math like this way, Second param in parseInt is for base, which is optional

var seconds = parseInt(123456, 10);

var days = Math.floor(seconds / (3600*24));
seconds  -= days*3600*24;
var hrs   = Math.floor(seconds / 3600);
seconds  -= hrs*3600;
var mnts = Math.floor(seconds / 60);
seconds  -= mnts*60;
console.log(days+" days, "+hrs+" Hrs, "+mnts+" Minutes, "+seconds+" Seconds");

Your given seconds 123456 would be 1 days, 10 Hrs, 17 Minutes, 36 Seconds not 1 days, 4 Hrs, 40 Minutes, 45 Seconds

Niklesh Raut
  • 34,013
  • 16
  • 75
  • 109
11
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
stopsopa
  • 408
  • 4
  • 20
4

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 "

timothyzhang
  • 730
  • 9
  • 12
4

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";
}
Big Sam
  • 1,290
  • 14
  • 7
4

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);
Jay
  • 740
  • 4
  • 8
  • 19
2

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'
user1063287
  • 10,265
  • 25
  • 122
  • 218
2

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(', ');
}
2

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.

  • 1
    While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Luca Kiebel Jan 24 '22 at 09:18
  • 1
    Edited, provided explanation as suggested by @Luca Kiebel – Heidi Maknow Jan 25 '22 at 12:58
1

You will probably find using epoch timestamps more straightforward: As detailed in Convert a Unix timestamp to time in JavaScript, the basic method is like so:

<script>
    // Create a new JavaScript Date object based on the timestamp
    // multiplied by 1000 so that the argument is in milliseconds, not seconds.
    var date1 = new Date();

    alert ('easy trick to waste a few seconds...' + date1);


    // var date = date2 - date1;

    // Hours part from the timestamp
    var hours1 = date1.getHours();
    // Minutes part from the timestamp
    var minutes1 = "0" + date1.getMinutes();
    // Seconds part from the timestamp
    var seconds1 = "0" + date1.getSeconds();


    var date2 = new Date();

    // Hours part from the timestamp
    var hours2 = date2.getHours();
    // Minutes part from the timestamp
    var minutes2 = "0" + date2.getMinutes();
    // Seconds part from the timestamp
    var seconds2 = "0" + date2.getSeconds();


    // Will display time in 10:30:23 format
    // var formattedTime = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);


    var  elapsedHrs = hours2 - hours1;
    var  elapsedMin = minutes2.substr(-2) -minutes1.substr(-2);
    var elapsedSec = seconds2.substr(-2) - seconds1.substr(-2);

    var elapsedTime = elapsedHrs + ' hours, ' + elapsedMin + ' minutes, ' + elapsedSec + ' seconds';

    alert ('time between timestamps: ' + elapsedTime);
</script>

Be warned that this script needs some work since for now it will give negative values for things like date1 = 12:00:00 and date2 = 12:00:05, but I'll leave that to you fo now.

You should rewrite your code to take a timestamp ( var x = new Date(); ) at the start of your timer and one whenever you are done/want to check elapsed time, and subtract the two before parsing out elapsed seconds, minutes, hours etc as required.

James Skemp
  • 8,018
  • 9
  • 64
  • 107
Hektor
  • 1,845
  • 15
  • 19
1

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);
        }
Svetoslav Marinov
  • 1,498
  • 14
  • 11
0

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