将以秒为单位给出的时间间隔转换为更易于理解的形式。

91
我需要一个代码片段,将给定的秒数转换为易于阅读的形式。函数应接收一个数字并输出像这样的字符串:
34 seconds 
12 minutes 
4 hours 
5 days 
4 months
1 year

不需要格式化,硬编码的格式将被删除。


3
可能是 如何将毫秒转换为人类可读形式? 的重复问题。 - nfechner
是的和不是,我在想这个问题有一个很好的 JavaScript 解决方案... - Dan
秒是一种可读性强的时间形式。 - nnnnnn
3
好的,“213123秒”并不易读。你可以提出一个更好的标题。 - Dan
26个回答

88
 function secondsToString(seconds)
{
var numyears = Math.floor(seconds / 31536000);
var numdays = Math.floor((seconds % 31536000) / 86400); 
var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
return numyears + " years " +  numdays + " days " + numhours + " hours " + numminutes + " minutes " + numseconds + " seconds";

}

1
谢谢!如果你添加检查复数(年/年份),那就更完美了! - Dan
感谢您的帮助,Royi。请看下面的答案,它完全回答了我的问题。 - Dan
5
并且这些神奇的数字:secondsInAYear = 31536000; secondsInADay = 86400; secondsInAnHour = 3600; secondsInAMinute = 60; - Jake Berger
4
注意:此内容不考虑闰年,并仅以“时间段”形式提供值。 - James Wilkins
1
(((seconds % 31536000) % 86400) % 3600) % 60 === seconds % 60 so you can save some bits that will die in your cpu `var numyears = Math.floor(seconds / 31536000); var numdays = Math.floor((seconds % 31536000) / 86400); var numhours = Math.floor((seconds % 86400) / 3600); var numminutes = Math.floor((seconds % 3600) / 60); var numseconds = seconds % 60;` - mr_tron

78

在 Royi 的帮助下,我们得到了一个输出时间间隔的人类可读形式的代码:

function millisecondsToStr (milliseconds) {
    // TIP: to find current time in milliseconds, use:
    // var  current_time_milliseconds = new Date().getTime();

    function numberEnding (number) {
        return (number > 1) ? 's' : '';
    }

    var temp = Math.floor(milliseconds / 1000);
    var years = Math.floor(temp / 31536000);
    if (years) {
        return years + ' year' + numberEnding(years);
    }
    //TODO: Months! Maybe weeks? 
    var days = Math.floor((temp %= 31536000) / 86400);
    if (days) {
        return days + ' day' + numberEnding(days);
    }
    var hours = Math.floor((temp %= 86400) / 3600);
    if (hours) {
        return hours + ' hour' + numberEnding(hours);
    }
    var minutes = Math.floor((temp %= 3600) / 60);
    if (minutes) {
        return minutes + ' minute' + numberEnding(minutes);
    }
    var seconds = temp % 60;
    if (seconds) {
        return seconds + ' second' + numberEnding(seconds);
    }
    return 'less than a second'; //'just now' //or other string you like;
}

5
这是错误的。对于像“3天0小时50分钟36秒”这样的时间,它只返回“3天”,因为当小时恰好为“0”时就会返回。 - user2909913
为了使其更相关,如果值不为0,则需要与变量连接。例如:let returnText = ''; if (days && days !== 0) { returntext += days + ' day' + numberEnding(days); } - Rahul Dhamecha
@user2909913 当天数不为0且小时数不为0时,它实际上会返回结果并向下取整到最近的单位(在某些情况下可能是可取的,因为在所有情况下都更短)。 - Tofandel

66

如果您对一个已经存在的非常好的JavaScript库感兴趣,您可能想要检查moment.js

更具体地说,与您的问题相关的moment.js部分是durations

以下是一些示例,展示如何利用它来完成您的任务:

var duration = moment.duration(31536000);

// Using the built-in humanize function:
console.log(duration.humanize());   // Output: "9 hours"
console.log(duration.humanize(true));   // Output: "in 9 hours"

moment.js内置支持50多种人类语言,因此如果您使用humanize()方法,则可以免费获得多语言支持。

如果您想要显示精确的时间信息,您可以利用moment-precise-range插件,该插件是专门为moment.js创建的。

console.log(moment.preciseDiff(0, 39240754000);
// Output: 1 year 2 months 30 days 5 hours 12 minutes 34 seconds

需要注意的一点是,目前 moment.js 不支持 duration 对象中的周/日(在一周中)。

希望这可以帮到你!


6
这相当不精确。moment.duration(40, 'seconds') 会得到 'a few seconds'moment.duration(45, 'seconds') 则会得到 'a minute'请参见此功能请求 - testworks
自2020年起,moment.js已被弃用。目前一个有用的维护库是humanize-duration - codeflorist

41

基于 @Royi 的回应,我进行了一次尝试:

/**
 * Translates seconds into human readable format of seconds, minutes, hours, days, and years
 * 
 * @param  {number} seconds The number of seconds to be processed
 * @return {string}         The phrase describing the amount of time
 */
function forHumans ( seconds ) {
    var levels = [
        [Math.floor(seconds / 31536000), 'years'],
        [Math.floor((seconds % 31536000) / 86400), 'days'],
        [Math.floor(((seconds % 31536000) % 86400) / 3600), 'hours'],
        [Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'minutes'],
        [(((seconds % 31536000) % 86400) % 3600) % 60, 'seconds'],
    ];
    var returntext = '';

    for (var i = 0, max = levels.length; i < max; i++) {
        if ( levels[i][0] === 0 ) continue;
        returntext += ' ' + levels[i][0] + ' ' + (levels[i][0] === 1 ? levels[i][1].substr(0, levels[i][1].length-1): levels[i][1]);
    };
    return returntext.trim();
}

我写的代码没有重复的if语句,而且不会像 0年0天30分钟1秒这样给你输出结果。

例如:

forHumans(60) 输出 1分钟

forHumans(3600) 输出 1小时

forHumans(13559879)则输出 156天 22小时 37分钟 59秒


1
如何使它更加友好,例如forHumans(13559879) -> 156天22小时37分钟和59秒?这应该是被接受的答案。 - Aaron Esau
链接现在已经失效。 - vidstige

16

尝试以下操作:

seconds = ~~(milliseconds / 1000);
minutes = ~~(seconds / 60);
hours = ~~(minutes / 60);
days = ~~(hours / 24);
weeks = ~~(days / 7);
year = ~~(days / 365);

注意:

  • 一般年份有365天,闰年有366天,因此如果这对你有影响,需要进行额外检查。
  • 夏令时也会产生类似的问题。当时间改变时,某些日子会有23个小时,而其他日子则有25个小时。

结论:这是一个粗鲁但简单的片段 :)


根据基准测试显示parseInt太慢,我稍微修改了您的代码。 - Dan
这样是不起作用的。例如,如果毫秒为300000(5分钟),那么这将给出毫秒= 300000,秒= 300,分钟= 5,这不是OP请求的输出。https://jsfiddle.net/yp6fcacs/ - Nathan

15

更加简单易读。

milliseconds = 12345678;
mydate=new Date(milliseconds);
humandate=mydate.getUTCHours()+" hours, "+mydate.getUTCMinutes()+" minutes and "+mydate.getUTCSeconds()+" second(s)";

结果为:

"3小时25分45秒"


1
这是一个非常好的答案,如果我需要输出一个“公元”的日期,那么这将是被接受的答案。相反,我需要将一个时间间隔转换为像“1个月前”这样的字符串。完全是我的错,我的问题没有表述清楚。多亏了你的提醒,问题得到了更新。 - Dan
对于那些需要处理日期和时间间隔的人来说,这是一个非常有趣的陷阱。如果我们从0开始计算纪元,而不是从1970年开始计算,则此问题将不存在。 - Dan
你的代码在时间间隔小于一年且未考虑夏令时时运行良好。 - Dan
@Dan 我是故意这么做的,为了考虑夏令时,请从所有最后一行中删除UTC。 - Zibri

14
millisToTime = function(ms){

    x = ms / 1000;
    seconds = Math.round(x % 60);
    x /= 60;
    minutes = Math.round(x % 60);
    x /= 60;
    hours = Math.round(x % 24);
    x /= 24;
    days = Math.round(x);

    return {"Days" : days, "Hours" : hours, "Minutes" : minutes, "Seconds" : seconds};
}

这将以整数形式表示毫秒,并给您一个包含所有可能需要的信息的 JSON 对象


2
感谢提供此函数。在我的情况下,我需要将 Math.round(x) 更改为 Math.floor(x) 以获取我所需的数字。 - Hong

10
把毫秒时间转换成易于阅读的格式。
 function timeConversion(millisec) {

        var seconds = (millisec / 1000).toFixed(1);

        var minutes = (millisec / (1000 * 60)).toFixed(1);

        var hours = (millisec / (1000 * 60 * 60)).toFixed(1);

        var days = (millisec / (1000 * 60 * 60 * 24)).toFixed(1);

        if (seconds < 60) {
            return seconds + " Sec";
        } else if (minutes < 60) {
            return minutes + " Min";
        } else if (hours < 24) {
            return hours + " Hrs";
        } else {
            return days + " Days"
        }
    }

"Out Put Sample"


我总是最喜欢这种风格。 - Mr. Developerdude

5
感谢@Dan / @Royi 提供的逻辑。但是实现没有生成像XX天,XX分钟这样的构建时间字符串。我稍微调整了他们的代码:
function millisecondsToStr( milliseconds ) {
    let temp = milliseconds / 1000;
    const years = Math.floor( temp / 31536000 ),
          days = Math.floor( ( temp %= 31536000 ) / 86400 ),
          hours = Math.floor( ( temp %= 86400 ) / 3600 ),
          minutes = Math.floor( ( temp %= 3600 ) / 60 ),
          seconds = temp % 60;

    if ( days || hours || seconds || minutes ) {
      return ( years ? years + "y " : "" ) +
      ( days ? days + "d " : "" ) +
      ( hours ? hours + "h " : ""  ) +
      ( minutes ? minutes + "m " : "" ) +
      Number.parseFloat( seconds ).toFixed( 2 ) + "s";
    }

    return "< 1s";
}

当一个人运行它时。
console.log("=", millisecondsToStr( 1540545689739 - 1540545684368 ));
console.log("=", millisecondsToStr( 351338536000 ));

结果看起来像这样:
= 5.37s
= 11y 51d 10h 2m 16.00s

5

除了众多方法之外,这里提供了一种廉价且简短的方式,只需一个时间单位即可检索出可读的时间。

const timeScalars = [1000, 60, 60, 24, 7, 52];
const timeUnits = ['ms', 'secs', 'mins', 'hrs', 'days', 'weeks', 'years'];

const getHumanReadableTime = (ms, dp = 0) => {
  let timeScalarIndex = 0, scaledTime = ms;

  while (scaledTime > timeScalars[timeScalarIndex]) {
    scaledTime /= timeScalars[timeScalarIndex++];
  }

  return `${scaledTime.toFixed(dp)} ${timeUnits[timeScalarIndex]}`;
};

例子输出:

getHumanReadableTime(512000);
getHumanReadableTime(5120000);
getHumanReadableTime(51200000);
getHumanReadableTime(51200000, 2);
getHumanReadableTime(51200000, 6);

/*

Output:
    '9 min'
    '1 hrs'
    '14 hrs'
    '14.22 hrs'
    '14.222222 hrs'

*/

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