How to convert seconds to HH:mm:ss in moment.js
Asked Answered
I

12

126

How can I convert seconds to HH:mm:ss?

At the moment I am using the function below

render: function (data){
     return new Date(data*1000).toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");;
}

This works on chrome but in firefox for 12 seconds I get 01:00:12 I would like to use moment.js for cross browser compatibility

I tried this but does not work

render: function (data){
         return moment(data).format('HH:mm:ss');
}

What am I doing wrong?

EDIT

I managed to find a solution without moment.js which is as follow

return (new Date(data * 1000)).toUTCString().match(/(\d\d:\d\d:\d\d)/)[0];

Still curious on how I can do it in moment.js

Inflection answered 10/7, 2015 at 9:33 Comment(12)
#6313493Overestimate
@Overestimate Sorry for not having mentioned that I have already read that post. I need to render a table with millions of row and the solution there is too slow. the second answer is exactly what I have written in my question but gives me problems in firefoxInflection
@QuentinTanioartino so 4 trivial math operators is a problem for the task of mutating DOM for millions of elements? Are you sure you understand the performance problem correctly?Meadowlark
@Meadowlark well I know that my DAO classes have to be rewritten to serve the data already converted. This is an issue I am aware off. Said that I am quite happy with the current performances of my first attempt but when I have 5 math operations for a conversion that slows the system a bit. Yes I agree with you that this is just a quick TEMPORARY solutionInflection
@QuentinTanioartino "that slows the system a bit" --- "a bit" is not how you reason about performance. Is it a bottleneck? Is it proven to be a bottleneck? If not - what drives you to optimize this very operation?Meadowlark
Moment: https://mcmap.net/q/35665/-convert-seconds-to-hh-mm-ss-with-javascript - sounds slowOverestimate
@Overestimate it will fail when it's summer/winter time boundariesMeadowlark
Ah - another reason not to use moment - one could set the start date to jan 1st thoughOverestimate
@Meadowlark Looking at the console the load is of 412 ms against 365 ms. So 47 ms difference.Inflection
@QuentinTanioartino okay. So? You spent 34 minutes trying to optimize a problem that saves 47ms to render a million DOM nodes (which will take > 10 seconds). I think it's a great result*. * Actually it's not. PS: "412 ms against 365 ms" --- I'm sure now we need to guess what exactly these 2 numbers mean (since you didn't explain how the tests have been conducted)Meadowlark
@Meadowlark the reason why I spent 34 minutes is because it didn't work on Firefox. In order to rewrite the server side it will take me two weeks :( . I understand this is not purist although. Thank you very much for your helpInflection
Here is a solution without using moment js or regular expression : new Date(SECONDS * 1000).toISOString().substr(11, 8);Bookmobile
O
97

From this post I would try this to avoid leap issues

moment("2015-01-01").startOf('day')
    .seconds(s)
    .format('H:mm:ss');

I did not run jsPerf, but I would think this is faster than creating new date objects a million times

function pad(num) {
    return ("0"+num).slice(-2);
}
function hhmmss(secs) {
  var minutes = Math.floor(secs / 60);
  secs = secs%60;
  var hours = Math.floor(minutes/60)
  minutes = minutes%60;
  return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
  // return pad(hours)+":"+pad(minutes)+":"+pad(secs); for old browsers
}

function pad(num) {
    return ("0"+num).slice(-2);
}
function hhmmss(secs) {
  var minutes = Math.floor(secs / 60);
  secs = secs%60;
  var hours = Math.floor(minutes/60)
  minutes = minutes%60;
  return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
  // return pad(hours)+":"+pad(minutes)+":"+pad(secs); for old browsers
}

for (var i=60;i<=60*60*5;i++) {
 document.write(hhmmss(i)+'<br/>');
}


/* 
function show(s) {
  var d = new Date();
  var d1 = new Date(d.getTime()+s*1000);
  var  hms = hhmmss(s);
  return (s+"s = "+ hms + " - "+ Math.floor((d1-d)/1000)+"\n"+d.toString().split("GMT")[0]+"\n"+d1.toString().split("GMT")[0]);
}    
*/
Overestimate answered 10/7, 2015 at 12:8 Comment(3)
You could do this in the second example: return [hours, minutes, seconds].filter(t => t).map(pad).join(":")Faxon
@OnnoFaber What do you think is the fastest? concatenation or a filter plus a map? We could also do `${pad(hours)}:${pad(minutes)}:${pad(secs)}`Overestimate
From all the answers before, the most simple is the one of mplungjan, but it has an error that shows random numbers if the value has milliseconds (for example: 17.3 s). Based on his code, I propose the following: function pad(num) { return ("0" + num).slice(-2); } /** * @return {string} */ export default function renderUserTime (seconds){ let minutes = Math.floor(seconds / 60); const outputSecs = Math.round(seconds % 60); let hours = Math.floor(minutes / 60); const outputMinutes = Math.round(minutes % 60); return `${pad(hours)}:${pad(outputMiUnderglaze
C
158

This is similar to the answer mplungjan referenced from another post, but more concise:

const secs = 456;

const formatted = moment.utc(secs*1000).format('HH:mm:ss');

document.write(formatted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>

It suffers from the same caveats, e.g. if seconds exceed one day (86400), you'll not get what you expect.

Cenac answered 4/5, 2017 at 15:30 Comment(4)
thank you, i think this is a very common need, open a pull request to moment.js they should incorporate it.Resoluble
Thanks @Sophie. Few places mention utc(), which is exactly what was needed in my case.Dahlberg
Thats not work with seconds more as 24 hours like 90000 seconds.Viscardi
@Sophie, it's not working for large second numbers.Sheffy
O
97

From this post I would try this to avoid leap issues

moment("2015-01-01").startOf('day')
    .seconds(s)
    .format('H:mm:ss');

I did not run jsPerf, but I would think this is faster than creating new date objects a million times

function pad(num) {
    return ("0"+num).slice(-2);
}
function hhmmss(secs) {
  var minutes = Math.floor(secs / 60);
  secs = secs%60;
  var hours = Math.floor(minutes/60)
  minutes = minutes%60;
  return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
  // return pad(hours)+":"+pad(minutes)+":"+pad(secs); for old browsers
}

function pad(num) {
    return ("0"+num).slice(-2);
}
function hhmmss(secs) {
  var minutes = Math.floor(secs / 60);
  secs = secs%60;
  var hours = Math.floor(minutes/60)
  minutes = minutes%60;
  return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
  // return pad(hours)+":"+pad(minutes)+":"+pad(secs); for old browsers
}

for (var i=60;i<=60*60*5;i++) {
 document.write(hhmmss(i)+'<br/>');
}


/* 
function show(s) {
  var d = new Date();
  var d1 = new Date(d.getTime()+s*1000);
  var  hms = hhmmss(s);
  return (s+"s = "+ hms + " - "+ Math.floor((d1-d)/1000)+"\n"+d.toString().split("GMT")[0]+"\n"+d1.toString().split("GMT")[0]);
}    
*/
Overestimate answered 10/7, 2015 at 12:8 Comment(3)
You could do this in the second example: return [hours, minutes, seconds].filter(t => t).map(pad).join(":")Faxon
@OnnoFaber What do you think is the fastest? concatenation or a filter plus a map? We could also do `${pad(hours)}:${pad(minutes)}:${pad(secs)}`Overestimate
From all the answers before, the most simple is the one of mplungjan, but it has an error that shows random numbers if the value has milliseconds (for example: 17.3 s). Based on his code, I propose the following: function pad(num) { return ("0" + num).slice(-2); } /** * @return {string} */ export default function renderUserTime (seconds){ let minutes = Math.floor(seconds / 60); const outputSecs = Math.round(seconds % 60); let hours = Math.floor(minutes / 60); const outputMinutes = Math.round(minutes % 60); return `${pad(hours)}:${pad(outputMiUnderglaze
L
31

You can use moment-duration-format plugin:

var seconds = 3820;
var duration = moment.duration(seconds, 'seconds');
var formatted = duration.format("hh:mm:ss");
console.log(formatted); // 01:03:40
<!-- Moment.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>

<!-- moment-duration-format plugin -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-duration-format/1.3.0/moment-duration-format.min.js"></script>

See also this Fiddle

Upd: To avoid trimming for values less than 60-sec use { trim: false }:

var formatted = duration.format("hh:mm:ss", { trim: false }); // "00:00:05"
Lemmon answered 9/5, 2017 at 9:45 Comment(4)
There is a trade-off that needs to be looked at with your answer and @sophie's answer. While technically your solution will display a duration of "Time" as hh:mm:ss, it requires the extra plugin. Sophie's is a "Date" from the current point in time formatted to hh:mm:ss. If you removed the "utc" from Sophie's it could return incorrect information since it uses the epoch as the date and not the current point in time. Both answers work. Just something to think about and understand.Eolith
While here using the CDN and whatnot could add increased latency, it is generally dangerous to think of "including another library" as a negative tradeoff vs. implementing code yourself. This is a trap I see many developers fall into and ultimately wind up with less maintainable code.Stockjobber
for some reason if seconds < 60 then it just ends up unformattedCeramal
@DanielLizik, just add { trim: false }. E.g.: duration.format("hh:mm:ss", { trim: false });Lemmon
D
19
var seconds = 2000 ; // or "2000"
seconds = parseInt(seconds) //because moment js dont know to handle number in string format
var format =  Math.floor(moment.duration(seconds,'seconds').asHours()) + ':' + moment.duration(seconds,'seconds').minutes() + ':' + moment.duration(seconds,'seconds').seconds();
Duncan answered 11/5, 2017 at 9:41 Comment(0)
M
8

My solution for changing seconds (number) to string format (for example: 'mm:ss'):

const formattedSeconds = moment().startOf('day').seconds(S).format('mm:ss');

Write your seconds instead 'S' in example. And just use the 'formattedSeconds' where you need.

Marengo answered 1/10, 2020 at 14:33 Comment(1)
This was the answer that I was looking for. Great advice but keep in mind that if you want to have hours displayed as well, make sure to use HH:mm:ss and not hh:mm:ss otherwise you will get 12:**:** for durations less then 1 hour.Benzidine
H
6

The above examples may work for someone but none did for me, so I figure out a much simpler approach

  var formatted = moment.utc(seconds*1000).format("mm:ss");
  console.log(formatted);
Harpsichord answered 30/7, 2021 at 2:6 Comment(0)
D
5

In a better way to utiliza moments.js; you can convert the number of seconds to human-readable words like ( a few seconds, 2 minutes, an hour).

Example below should convert 30 seconds to "a few seconds"

moment.duration({"seconds": 30}).humanize()

Other useful features: "minutes", "hours"

Detrimental answered 8/3, 2021 at 17:18 Comment(0)
H
4

Until 24 hrs. As Duration.format is deprecated, with [email protected]

const seconds = 123;
moment.utc(moment.duration(seconds,'seconds').as('milliseconds')).format('HH:mm:ss');
Humanity answered 11/5, 2020 at 2:40 Comment(0)
S
1

How to correctly use moment.js durations? | Use moment.duration() in codes

First, you need to import moment and moment-duration-format.

import moment from 'moment';
import 'moment-duration-format';

Then, use duration function. Let us apply the above example: 28800 = 8 am.

moment.duration(28800, "seconds").format("h:mm a");

🎉Well, you do not have above type error. 🤔Do you get a right value 8:00 am ? No…, the value you get is 8:00 a. Moment.js format is not working as it is supposed to.

💡The solution is to transform seconds to milliseconds and use UTC time.

moment.utc(moment.duration(value, 'seconds').asMilliseconds()).format('h:mm a')

All right we get 8:00 am now. If you want 8 am instead of 8:00 am for integral time, we need to do RegExp

const time = moment.utc(moment.duration(value, 'seconds').asMilliseconds()).format('h:mm a');
time.replace(/:00/g, '')
Shandishandie answered 8/5, 2020 at 9:1 Comment(0)
P
0

To display number of days along with hours, mins and seconds, you can do something like this:

const totalSec = 126102;
const remainingMillies= (totalSec % 86400) * 1000;
const formatted = `${Math.floor(totalSec / 86400)} day(s) and ${moment.utc(remainingMillies).format('hh:mm:ss')}`;
console.log(formatted );

will output : 1 day(s) and 11:01:42

Plausible answered 31/10, 2021 at 15:50 Comment(0)
E
0

In 2022 no need for any new plugin just do this

Literally all you need in 2022 prints out duration in hh:mm:ss from two different date strings

<Moment format='hh:mm:ss' duration={startTime} date={endTime} />

Ergotism answered 1/9, 2022 at 11:8 Comment(0)
A
0

I think there's no need to use 3rd part libray/pluggin to get this task done
when using momentJS version 2.29.4 :

  private getFormatedDuration(start: Date, end: Date): string {
    // parse 'normal' Date values to momentJS values
    const startDate = moment(start);
    const endDate = moment(end);

    // calculate and convert to momentJS duration 
    const duration = moment.duration(endDate.diff(startDate));

    // retrieve wanted values from duration
    const hours = duration.asHours().toString().split('.')[0];
    const minutes = duration.minutes();

    // voilà ! without using any 3rd library ..
    return `${hours} h ${minutes} min`;
  }

supports also 24h format
PS : you can test and calculate by yourself using a 'decimal to time' calculator at CalculatorSoup

Asyllabic answered 27/10, 2022 at 16:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.