JavaScript Human-Readable Time Diff (“5 Hours Ago”, “Will Be In A Day”,…)

Some time ago, I’ve wrote an article iCompile – PHP Human-Readable Time Diff (“5 Hours Ago”, “Will Be In A Day”,…),
running the “main action” procedure in a recursive-loop, I could improve the spectrum of the result, so it will include also complex time-periods (“5 hours, 100 milliseconds”, “3 years, 12 days”, “3 days, 14 seconds”, etc…)
among other code improvements :)

[also available in my github’s gist: https://gist.github.com/eladkarako/65b3b395c5c9d5233f104eceeb7cede4]

```function human_time_diff(from, to){ /*accept unix-datetime integer, Date object or date string, fallback is current date*/
"use strict";

var now, diff;

/*---*/
function difference(diff){
var
MINUTE_IN_SECONDS = 60
, HOUR_IN_SECONDS   = 60  * MINUTE_IN_SECONDS
, DAY_IN_SECONDS    = 24  * HOUR_IN_SECONDS
, MONTH_IN_SECONDS  = 30  * DAY_IN_SECONDS
, YEAR_IN_SECONDS   = 365 * DAY_IN_SECONDS
, since
, milliseconds, seconds, minutes, hours, days, months, years
;

if(0 === diff){
since = "0 seconds";
}
else if(diff > 0 && diff < 1){
milliseconds = Math.trunc(diff * 1000);
since = milliseconds + " " + (1 === milliseconds ? "millisecond" : "milliseconds");
}
else if(diff >= 1 && diff < MINUTE_IN_SECONDS){
seconds = Math.trunc(diff);
seconds = Math.max(diff, 1);
since = seconds + " " + (1 === seconds ? "second" : "seconds");

diff = diff - (seconds);
if(diff > 0)
since = since + ", " + difference(diff);                             /* calculate leftover time, recursively */
}
else if(diff >= MINUTE_IN_SECONDS && diff < HOUR_IN_SECONDS){
minutes = Math.trunc(diff / MINUTE_IN_SECONDS);
minutes = Math.max(minutes, 1);
since = minutes + " " + (1 === minutes ? "minute" : "minutes");

diff  = diff - (minutes * MINUTE_IN_SECONDS);
if(diff > 0)
since = since + ", " + difference(diff);                             /* calculate leftover time, recursively */
}
else if(diff >= HOUR_IN_SECONDS && diff < DAY_IN_SECONDS){
hours = Math.trunc(diff / HOUR_IN_SECONDS);
hours = Math.max(hours, 1);
since = hours + " " + (1 === hours ? "hour" : "hours");

diff  = diff - (hours * HOUR_IN_SECONDS);
if(diff > 0)
since = since + ", " + difference(diff);                             /* calculate leftover time, recursively */
}
else if(diff >= DAY_IN_SECONDS && diff < MONTH_IN_SECONDS){
days = Math.trunc(diff / DAY_IN_SECONDS);
days = Math.max(days, 1);
since = days + " " + (1 === days ? "day" : "days");

diff  = diff - (days * DAY_IN_SECONDS);
if(diff > 0)
since = since + ", " + difference(diff);                             /* calculate leftover time, recursively */
}
else if(diff >= MONTH_IN_SECONDS && diff < YEAR_IN_SECONDS){
months = Math.trunc(diff / MONTH_IN_SECONDS);
months = Math.max(months, 1);
since = months + " " + (1 === months ? "month" : "months");

diff  = diff - (months * MONTH_IN_SECONDS);
if(diff > 0)
since = since + ", " + difference(diff);                             /* calculate leftover time, recursively */
}
else if (diff >= YEAR_IN_SECONDS){
years = Math.trunc(diff / YEAR_IN_SECONDS);
years = Math.max(diff, 1);
since = years + " " + (1 === years ? "year" : "years");

diff  = diff - (years * YEAR_IN_SECONDS);
if(diff > 0)
since = since + ", " + difference(diff);                             /* calculate leftover time, recursively */
}

return since;
}
/*---*/

now  = new Date();

from = ("number" === typeof from)                                                   ? Math.max(from, 0)      :
("string" === typeof from)                                                   ? Number(new Date(from)) :
("object" === typeof from && "date" === from.constructor.name.toLowerCase()) ? Number(from)           : Number(now)
;

to   = ("number" === typeof to)                                                     ? Math.max(to, 0)        :
("string" === typeof to)                                                     ? Number(new Date(to))   :
("object" === typeof to && "date" === to.constructor.name.toLowerCase())     ? Number(to)             : Number(now)

if("nan" === String(from).toLowerCase())  throw new Error("Error While Converting Date (first argument)" );
if("nan" === String(to).toLowerCase())    throw new Error("Error While Converting Date (second argument)");

diff = Math.abs(from - to);
console.log(from,to,diff);
return difference(diff);
}

/*
human_time_diff();                                // 0 seconds
human_time_diff("22:15:40");                      // ERROR (invalid date format)
human_time_diff(  Number(new Date()) - 2000  );   // 33 minutes, 20 seconds
human_time_diff( Number(new Date()) - 300 );      // 5 minutes
human_time_diff( Number(new Date()) - 300.123 );  // 5 minutes, 123 milliseconds
*/
```

Unix Snippet – Get File’s “Touch Date-Format” One-Liner

Pipelining the modification date from `stat` into an inline-date-phrase using the `date --date="@...` directive (using `read` to locate the pipeline’s output in the middle of the date-phrase),
And you’ve got yourself a nice little converter, which you can customise, to use *any* date-format,
I’ve using the Universal Time Coordinated standard.

```file name:          `my_file.txt`
unix time-format:   `1458036575`     (Asia/Jerusalem)
touch time-format:  `201603151009`   (UTC)```
```stat --format=%Y "my_file.txt" | { read -r tmp_date; date --utc --date="@\$tmp_date" "+%C%y%m%d%H%M"; }
```

*Ps.
You can easily use the touch-date-format with `touch` command using the following directive:
`touch -t 201603151009 --time=mtime my_file.txt;`
but make sure first you set the local-timezone to same timezone it was generated on.
`TZ=UTC` will help you do that,
`TZ=UTC; touch -t 201603151009 --time=mtime my_file.txt;` will apply it to the current line.
and you can also make sure of it is done right by using:
`export TZ=UTC` at the start of the script, and at the end of it just re-run
`export TZ=Asia/Jerusalem` (or whatever your TimeZone is) to come-back to your TimeZone,

Nice!

Moment.JS

```
```

momentjs.com
Parse, validate, manipulate, and display dates in javascript, easily.

supports diff. calculation, relative time verbosity (“before T minutes”), all this with multi-languages support too.

documentation area

plus, they use some lovely variation of NodeUnit for unit tests, one file-er, which is a really nice customization!
http://momentjs.com/tests/ ->
http://momentjs.com/static/js/core-test.js