Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moment JS duration humanize more precise

I have a moment duration of say 14 seconds.

const duration = moment.duration(end.diff(startTime));

If I want to display this duration as a formatted string, I can use .humanize()

duration.humanize(true)
// in a few seconds

This works fine, but is there a way for moment to format this as an exact duration like in 14 seconds or, for a longer duration, in in 2 days and 5 hours instead of in 2 days?

like image 538
hoan Avatar asked Dec 18 '18 08:12

hoan


2 Answers

I solved your problem with this snippet of code I made.

function formatDuration(period) {
    let parts = [];
    const duration = moment.duration(period);

    // return nothing when the duration is falsy or not correctly parsed (P0D)
    if(!duration || duration.toISOString() === "P0D") return;

    if(duration.years() >= 1) {
        const years = Math.floor(duration.years());
        parts.push(years+" "+(years > 1 ? "years" : "year"));
    }

    if(duration.months() >= 1) {
        const months = Math.floor(duration.months());
        parts.push(months+" "+(months > 1 ? "months" : "month"));
    }

    if(duration.days() >= 1) {
        const days = Math.floor(duration.days());
        parts.push(days+" "+(days > 1 ? "days" : "day"));
    }

    if(duration.hours() >= 1) {
        const hours = Math.floor(duration.hours());
        parts.push(hours+" "+(hours > 1 ? "hours" : "hour"));
    }

    if(duration.minutes() >= 1) {
        const minutes = Math.floor(duration.minutes());
        parts.push(minutes+" "+(minutes > 1 ? "minutes" : "minute"));
    }

    if(duration.seconds() >= 1) {
        const seconds = Math.floor(duration.seconds());
        parts.push(seconds+" "+(seconds > 1 ? "seconds" : "second"));
    }

    return "in "+parts.join(", ");
}

This function takes a period string (ISO 8601), parses it with Moment (>2.3.0) and then, for every unit of time, pushes a string in the parts array. Then everything inside the parts array gets joined together with ", " as separation string.

You can test it here: https://jsfiddle.net/mvcha2xp/6/

I'm using it as a Vue filter to humanize durations correctly.

like image 137
SyncroIT Avatar answered Sep 20 '22 12:09

SyncroIT


You can customize the output of relative time functions like humanize() using relativeTime key of updateLocale and relativeTimeThreshold.

I don't know what is your expected output for a generic duration, but you can use the following code to get in 14 seconds for a duration of 14 seconds:

const startTime = moment();
const end = moment().add(14, 'seconds');
const duration = moment.duration(end.diff(startTime));
console.log( duration.humanize(true) );

moment.relativeTimeThreshold('ss', 60);
moment.updateLocale('en', {
  relativeTime : {
    s: function (number, withoutSuffix, key, isFuture){
      return number + ' seconds';
    }
  }
});

console.log( moment.duration(end.diff(startTime)).humanize(true) );
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>

You can also take a look at this and this similar questions.

like image 32
VincenzoC Avatar answered Sep 18 '22 12:09

VincenzoC