用JavaScript将秒转换为HH-MM-SS?

394

如何使用JavaScript将秒数转换为HH-MM-SS格式的字符串?


3
请看我在https://dev59.com/JG015IYBdhLWcg3w7wMW#6313008的回答。 - powtac
38个回答

564

您可以使用JavaScript日期方法来完成此操作,而无需任何外部JavaScript库,方法如下:

您可以使用JavaScript日期方法来完成此操作,而无需任何外部JavaScript库,方法如下:

const date = new Date(null);
date.setSeconds(SECONDS); // specify value for SECONDS here
const result = date.toISOString().slice(11, 19);

或者,根据@Frank的评论; 一个简单明了的表述:

new Date(SECONDS * 1000).toISOString().slice(11, 19);

47
我不知道为什么每个人都要添加额外的库或者手动计算,而这个方法已经完美地解决了问题。谢谢! - jminardi
157
可以将其简化为一行代码:new Date(SECONDS * 1000).toISOString().substr(11, 8);(注:SECONDS是一个变量,表示以秒为单位的时间值) - Frank
5
太棒了。没有使用任何第三方库。这是最好的。 - Riz
78
这种方法的问题在于,24小时后会溢出,无法显示超过这段时间的内容。如果你需要显示少于24小时的时间长度,那么这是一个完美的解决方案。 - Renato Gama
2
这在IE11中对我不起作用,我收到“对象不支持' toISOString '属性或方法”的错误信息。 - NibblyPig
显示剩余10条评论

375

更新(2020年):

请使用@Frank的一行解决方案:

new Date(SECONDS * 1000).toISOString().substring(11, 16)

如果SECONDS<3600,并且如果您只想显示MM:SS,则使用以下代码:

new Date(SECONDS * 1000).toISOString().substring(14, 19)

这绝对是最佳解决方案。


旧版回答:

使用Moment.js库。


27
虽然Moment.js不算太大,但如果你只是用它把秒数转换成hh:mm:ss的格式,似乎有点过头了。最好使用这些答案中提到的函数或其他函数来实现。 - Ola Karlsson
7
这个答案在某种程度上是错误的。如果数量超过86400秒会发生什么?;) - Vitor Tyburski
5
我认为另一个解决方案比在其中添加另一个 JS 库更好。 - Daniel Viglione
5
为了一个简单的操作添加库,我认为不应该接受这个答案。是的,这确实可以解决问题,但有更好的解决方案!!! - Andris
4
将这个库用于像这样的一个小任务,会为您的项目添加 59,024字节 的代码,而使用约 53字节 的代码就可以获得相同的效果...来自于下方链接new Date(SECONDS * 1000).toISOString().substr(11, 8); - ashleedawg
显示剩余8条评论

214

我认为标准Date对象的任何内置功能都不能比自己计算更方便地完成此任务。

hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
minutes = Math.floor(totalSeconds / 60);
seconds = totalSeconds % 60;

示例:

let totalSeconds = 28565;
let hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
let minutes = Math.floor(totalSeconds / 60);
let seconds = totalSeconds % 60;

console.log("hours: " + hours);
console.log("minutes: " + minutes);
console.log("seconds: " + seconds);

// If you want strings with leading zeroes:
minutes = String(minutes).padStart(2, "0");
hours = String(hours).padStart(2, "0");
seconds = String(seconds).padStart(2, "0");
console.log(hours + ":" + minutes + ":" + seconds);


这是最正确的答案,因为如果超过24小时它不会溢出。 - Accountant م
边缘情况,但需要注意:假设一个值totalSeconds = 1739.8395。(T.J.在上面的评论中提到了小数部分。)公式计算出“秒”为59.839500000000044。如果一个人想要四舍五入,那么59秒就变成了60秒。这意味着,“秒”值需要设置为0,并且需要将1分钟添加到“分钟”中。如果“分钟”值恰好为59,则“分钟”值变为60,因此“分钟”需要重置为0,并且需要将1小时添加到“小时”中。 - mg1075
@mg1075 - 最简单的解决方案是从totalSeconds = Math.round(totalSeconds);开始。 :-) - T.J. Crowder
相关链接:https://dev59.com/yG855IYBdhLWcg3woV_M - djvg

131

我知道这有点过时,但是...

ES2015:

var toHHMMSS = (secs) => {
    var sec_num = parseInt(secs, 10)
    var hours   = Math.floor(sec_num / 3600)
    var minutes = Math.floor(sec_num / 60) % 60
    var seconds = sec_num % 60

    return [hours,minutes,seconds]
        .map(v => v < 10 ? "0" + v : v)
        .filter((v,i) => v !== "00" || i > 0)
        .join(":")
}

它将输出:

toHHMMSS(129600) // 36:00:00
toHHMMSS(13545) // 03:45:45
toHHMMSS(180) // 03:00
toHHMMSS(18) // 00:18

2
那么,毫秒级别的时间呢?03:45:45.xxx? - Mike Stoddart

44

正如Cleiton在他的回答中指出的那样,可以使用moment.js实现此目的:

moment().startOf('day')
        .seconds(15457)
        .format('H:mm:ss');

9
如果秒数超过一天会发生什么? - Gilad Peleg
3
如果秒数超过了一天,它会在内部计算出天数,并仅返回剩余的小时、分钟和秒数。如果你想同时计算天数,可以尝试使用 moment().startOf('year').seconds(30000000).format('DDD HH:mm:ss') - elquimista
10
如果秒数超过一年会发生什么? - OrangePot
4
如果秒数超过一年,程序会自动计算年数,并返回剩余的天数、小时数、分钟数和秒数。如果您想要同时计算年数,可以尝试使用.format('YYYY DDD HH:mm:ss') - David Callanan
1
但这不能是可选的。那看起来可能很丑。 - shaedrich

26

这是一个简单的时间转换函数,可能会对您有所帮助

function formatSeconds(seconds) {
    var date = new Date(1970,0,1);
    date.setSeconds(seconds);
    return date.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");
}

2
formatSeconds(3919); //返回 01:05:19非常优秀的函数..喜欢它 - Samrat Saha
如之前所说,这将在24小时后溢出。 - PaulCrp

19
这就是诀窍:
function secondstotime(secs)
{
    var t = new Date(1970,0,1);
    t.setSeconds(secs);
    var s = t.toTimeString().substr(0,8);
    if(secs > 86399)
        s = Math.floor((t - Date.parse("1/1/70")) / 3600000) + s.substr(2);
    return s;
}

(来源于这里


14
var  timeInSec = "661"; //even it can be string

String.prototype.toHHMMSS = function () { 
   /* extend the String by using prototypical inheritance */
    var seconds = parseInt(this, 10); // don't forget the second param
    var hours   = Math.floor(seconds / 3600);
    var minutes = Math.floor((seconds - (hours * 3600)) / 60);
    seconds = seconds - (hours * 3600) - (minutes * 60);

    if (hours   < 10) {hours   = "0"+hours;}
    if (minutes < 10) {minutes = "0"+minutes;}
    if (seconds < 10) {seconds = "0"+seconds;}
    var time    = hours+':'+minutes+':'+seconds;
    return time;
}

alert("5678".toHHMMSS());   // "01:34:38"
console.log(timeInSec.toHHMMSS());   //"00:11:01"

我们可以让这个函数变得更短,更简洁,但这会降低可读性,因此我们将尽可能简单和稳定地编写它。
或者您可以在这里检查它的运作here

此外,如果您想轻松处理所有日期时间事务,请使用MomentJS。 - Sheelpriy
谢谢!浏览器扩展中不需要包含库。简单而且有效! - Arlo

13

我认为最一般(而且晦涩)的解决方案可能是这个

function hms(seconds) {
  return [3600, 60]
    .reduceRight(
      (pipeline, breakpoint) => remainder =>
        [Math.floor(remainder / breakpoint)].concat(pipeline(remainder % breakpoint)),
      r => [r]
    )(seconds)
    .map(amount => amount.toString().padStart(2, '0'))
    .join('-');
}

或者复制并粘贴最短的版本

function hms(seconds) {
  return [3600, 60]
    .reduceRight(
      (p, b) => r => [Math.floor(r / b)].concat(p(r % b)),
      r => [r]
    )(seconds)
    .map(a => a.toString().padStart(2, '0'))
    .join('-');
}

一些示例输出:

> hms(0)
< "00-00-00"

> hms(5)
< "00-00-05"

> hms(60)
< "00-01-00"

> hms(3785)
< "01-03-05"

> hms(37850)
< "10-30-50"

> hms(378500)
< "105-08-20"

工作原理

算法

  1. 要获取小时数,需要将总秒数除以3600并向下取整。
  2. 要获取分钟数,需要将余数除以60并向下取整。
  3. 要获取秒数,只需使用余数即可。

将每个时间单位的值保留在数组中以便于格式化更加方便。

例如,对于输入的3785秒,输出应该是[1, 3, 5],即1小时,3分钟和5秒。

创建管道

通过将3600和60常量命名为“分界点”,您可以将此算法编写为函数,如下所示:

function divideAndAppend(remainder, breakpoint, callback) {
  return [Math.floor(remainder / breakpoint)].concat(callback(remainder % breakpoint));
}

它返回一个数组,其中第一项是给定断点的金额,其余数组由回调函数给出。 在回调函数中重复使用divideAndAppend将为您提供一系列组合的divideAndAppend函数。每个函数都会计算给定断点的金额并将其附加到数组中,生成所需的输出。

然后,您还需要一个“最终”回调函数来结束此管道。换句话说,您已经使用了所有断点,现在只剩下余数。 由于您已经在第3步得到答案,因此应该使用某种身份函数,在本例中为remainder => [remainder]

现在,您可以按以下方式编写管道:

let pipeline = r3 => divideAndAppend(
    r3, 
    3600, 
    r2 => divideAndAppend(
        r2, 
        60, 
        r1 => [r1]));

> pipeline(3785)
< [1, 3, 5]

很酷,对吧?

使用for循环进行泛化

现在你可以使用可变数量的断点来泛化,并创建一个for循环,将单独的divideAndAppend函数组合成管道。 你从身份函数r1 => [r1]开始,然后使用60断点,最后使用3600断点。

let breakpoints = [60, 3600];
let pipeline = r => [r];

for (const b of breakpoints) {
  const previousPipeline = pipeline;
  pipeline = r => divideAndAppend(r, b, previousPipeline);
}

> pipeline(3785)
< [1, 3, 5]

使用 Array.prototype.reduce()

现在,您可以将此 for 循环重写为 reducer,以获得更短、更函数化的代码。换句话说,将函数组合重写为 reducer。

let pipeline = [60, 3600].reduce(
  (ppln, b) => r => divideAndAppend(r, b, ppln),
  r => [r]
);

> pipeline(3785)
< [1, 3, 5]

累加器ppln是管道,您正在使用其先前版本进行组合。最初的管道是r => [r]

现在您可以将函数divideAndAppend内联,并使用Array.prototype.reduceRight,它与[].reverse().reduce(...)相同,使断点定义更加自然。

let pipeline = [3600, 60]
    .reduceRight(
      (ppln, b) => r => [Math.floor(r / b)].concat(ppln(r % b)),
      r => [r]
    );

哪个是最终形式。然后,您只需将左侧填充了 0 的字符串映射到字符串,并使用:分隔符连接字符串;

更多泛化

将reducer包装成函数

function decompose(total, breakpoints) {
  return breakpoints.reduceRight(
    (p, b) => r => [Math.floor(r / b)].concat(p(r % b)),
    r => [r]
  )(total);
}

> decompose(3785, [3600, 60])
< [1, 3, 5]

现在您可以使用非常通用的算法。例如:

轻松转换(奇怪的)美国长度标准

给定以下标准

单位 划分
1 英尺 12 英寸
1 码 3 英尺
1 英里 1760 码
> decompose(123_456, [1760 * 3 * 12, 3 * 12, 12])
< [1, 1669, 1, 0]

123456 英寸 = 1 英里、1669 码、1 英尺和 0 英寸

或者你可以将其转换为十进制或二进制表示形式

> decompose(123_456, [100_000, 10_000, 1000, 100, 10])
< [1, 2, 3, 4, 5, 6]

> decompose(127, [128, 64, 32, 16, 8, 4, 2])
< [0, 1, 1, 1, 1, 1, 1, 1]

支持浮点数断点的工作

由于JavaScript支持使用浮点数进行mod运算,因此您也可以执行以下操作

> decompose(26.5, [20, 2.5])
< [1, 2, 1.5]

没有断点的边缘情况也自然被覆盖

> decompose(123, [])
< [123]

10

试一下这个:

function toTimeString(seconds) {
  return (new Date(seconds * 1000)).toUTCString().match(/(\d\d:\d\d:\d\d)/)[0];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接