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


当前回答

在JavaScript Date方法的帮助下,你可以在没有任何外部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);

其他回答

我认为标准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);

下面是一个函数,根据powtac的答案将秒转换为hh-mm-ss格式

斯菲德尔

/** 
 * Convert seconds to hh-mm-ss format.
 * @param {number} totalSeconds - the total seconds to convert to hh- mm-ss
**/
var SecondsTohhmmss = function(totalSeconds) {
  var hours   = Math.floor(totalSeconds / 3600);
  var minutes = Math.floor((totalSeconds - (hours * 3600)) / 60);
  var seconds = totalSeconds - (hours * 3600) - (minutes * 60);

  // round seconds
  seconds = Math.round(seconds * 100) / 100

  var result = (hours < 10 ? "0" + hours : hours);
      result += "-" + (minutes < 10 ? "0" + minutes : minutes);
      result += "-" + (seconds  < 10 ? "0" + seconds : seconds);
  return result;
}

示例使用

var seconds = SecondsTohhmmss(70);
console.log(seconds);
// logs 00-01-10

对于任何使用AngularJS的人来说,一个简单的解决方案是使用date API来过滤值,它会根据请求的格式将毫秒转换为字符串。例子:

<div>Offer ends in {{ timeRemaining | date: 'HH:mm:ss' }}</div>

请注意,这需要毫秒,所以如果从秒转换(就像最初的问题一样),可能需要将timerremain乘以1000。

这招很管用:

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;
}

(来源此处)

我认为最普遍(也是最神秘)的解决方案可能是这样的

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"

它是如何工作的

算法

要得到小时数,你需要用总秒数除以3600,然后取底。 要得到分钟数,你需要用余数除以60,然后取底。 要得到秒数,你只需用余数。

将单个金额保存在一个数组中也很好,以便于格式化。

例如,给定3785s的输入,输出应该是[1,3,5],即1小时3分5秒。

创建管道

将3600和60个常量命名为“断点”,您可以将此算法写成如下函数

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

它返回一个数组,其中第一项是给定断点的数量,数组的其余部分由回调函数给出。 重用回调函数中的divideAndAppend将为您提供一个组合的divideAndAppend函数的管道。每一个 计算每个给定断点的数量,并将其附加到生成所需输出的数组中。

然后,您还需要“final”回调来结束这个管道。换句话说,您使用了所有的断点,现在只剩下其余的。 既然你已经在3)处得到了答案,你应该使用某种恒等函数,在这种情况下,remainder =>[余数]。

现在可以像这样编写管道

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

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

酷吧?

使用for-loop泛化

现在,您可以使用可变数量的断点进行泛化,并创建一个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,以获得更短、更实用的代码。换句话说,重写函数组合成减速器。

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

这是最终形式。然后你只需appy映射到字符串与填充0的左边和连接字符串:分隔符;

更多的推广

将减速器包装成功能

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]

你现在有了一个非常通用的算法。例如:

容易转换(奇怪的)我们的长度标准

考虑到标准

Unit Divisions
1 foot 12 inches
1 yard 3 feet
1 mile 1760 yards
> 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]