如何在 moment.js / JavaScript 中使这段完整的持续时间更加人性化

13
我有一个用于文件上传的“剩余时间”计数器。 剩余时间是这样计算并转换成毫秒的:

我有一个用于文件上传的“剩余时间”计数器。剩余持续时间是这样计算并转换为毫秒的:

var elapsedTime = e.timeStamp - timestarted;
var speed = e.loaded / elapsedTime;
var estimatedTotalTime = e.totalSize / speed;
var timeLeftInSeconds = (estimatedTotalTime - elapsedTime) / 1000;

我接下来建立了一个数组,准备将其转换为可读的字符串。该数组如下:

var time = {
              years : Math.round(moment.duration(timeLeftInSeconds, 'milliseconds').years()),
              months : Math.round(moment.duration(timeLeftInSeconds, 'milliseconds').months()),
              days : Math.round(moment.duration(timeLeftInSeconds, 'milliseconds').days()),
              hours : Math.round(moment.duration(timeLeftInSeconds, 'milliseconds').hours()),
              minutes : Math.round(moment.duration(timeLeftInSeconds, 'milliseconds').minutes()),
              seconds : Math.round(moment.duration(timeLeftInSeconds, 'milliseconds').seconds())
};

这一切都完美地运行,如果我输出这些数据的字符串表示形式,如下所示:

  console.log(time.years + ' years, ' + time.months + ' months, ' + time.days + ' days, ' + time.hours + ' hours, '+ time.minutes + ' minutes, ' + time.seconds + ' seconds');

它会返回一个简洁易懂的剩余时间流,像这样:

0 years, 0 months, 0 days, 0 hours, 1 minutes, 7 seconds
现在我需要的是让输出结果更加贴近人性化,使字符串根据剩余时间来构建。例如:
  • 剩余2年零3个月
  • 剩余1小时32分钟41秒
  • 剩余7秒
  • 剩余3分钟46秒
  • 剩余6秒

等等……

现在我知道 moment.js 可以自动将持续时间转换为更易懂的文本,但它适用于单个值,而这里可能涉及到多个值(如小时/分钟/秒)。

我该如何使用 moment.js 或手动构建字符串来实现数据的人性化呈现?

提前致谢。

4个回答

13

我的HumanizeDuration.js库似乎正是你想要的:

humanizeDuration(1);         // "1 millisecond"
humanizeDuration(3000);      // "3 seconds"
humanizeDuration(2012);      // "2 seconds, 12 milliseconds"
humanizeDuration(97320000);  // "1 day, 3 hours, 2 minutes"

看起来我回答有点晚了,但也许会对其他查看这个问题的人有所帮助!


10

我认为你最好的选择是这样的:

function humanize(time){
    if(time.years   > 0){   return time.years   + ' years and '     + time.months   + ' months remaining';}
    if(time.months  > 0){   return time.months  + ' months and '    + time.days     + ' days remaining';}
    if(time.days    > 0){   return time.days    + ' days and '      + time.hours    + ' hours remaining';}
    if(time.hours   > 0){   return time.hours   + ' hours and '     + time.minutes  + ' minutes and ' + time.seconds + ' seconds remaining';}
    if(time.minutes > 0){   return time.minutes + ' minutes and '   + time.seconds  + ' seconds remaining';}
    if(time.seconds > 0){   return time.seconds + ' seconds remaining';}
    return "Time's up!";
}

或者,你可以使用这个函数:

function humanize(time){
    var o = '';
    for(key in time){
        if(time[key] > 0){
            if(o === ''){
                o += time[key] + ' ' + key + ' ';
            }else{
                return o + 'and ' + time[key] + ' ' + key + ' remaining';
            }
        }
    }
    return o + 'remaining';
}

它返回最大的前两个值的"x <time>和y <time> remaining"。(或在最后一种情况下仅返回秒数。


谢谢Cerberus,我考虑过做类似的事情(尽管是通过数组循环),但如果持续时间很长,比如2年,我只想返回年份;而对于较短的持续时间,我希望返回几个部分(3分钟42秒)。我原本以为moment.js已经处理了这个问题,但看来并不是这样。 - gordyr
@gordyr:完全没有问题 :D - Cerbrus
抱歉Cerbrus,我刚刚意识到我最终使用的函数实际上是由用户1933818在你编辑答案之前发布的。我觉得他应该获得正确答案的荣誉。希望你能理解。干杯! - gordyr
@gordyr: 什么?那个东西我自己写的!他在13:02:59发布的。我最后一次编辑代码是在12:56:25。那个家伙明显抄袭了我的答案的一半。他是在我最后一次编辑之后发布的。 - Cerbrus
@gordyr:另一个答案已被删除。 - Cerbrus
多么奇怪啊...在我的端上看起来他早就写好了...对不起,伙计!这是我第一次在SO上看到这种情况!!希望现在都解决了!再次感谢! - gordyr

4

你应该尝试一下这个插件:moment-duration-format

它的语法非常方便:

var moment = require('moment');
require("moment-duration-format");
moment.duration(32832, "seconds").format("h [hrs]: m [min]: s [sec]")
// => 9 hrs: 7 min: 12 sec" 

0

我最终对date-fns的formatDistanceToNow感到满意。您可以添加该函数,而无需像moment.js一样添加整个库。


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