# 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
*/
```

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

Code Ripped From WordPress Trunk And Modified To Not Requiring Translator Objects (Use Plain en_US Default).

```
// Constants for expressing human-readable intervals
// in their respective number of seconds.
define('MINUTE_IN_SECONDS', 60);
define('HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS);
define('DAY_IN_SECONDS', 24 * HOUR_IN_SECONDS);
define('WEEK_IN_SECONDS', 7 * DAY_IN_SECONDS);
define('YEAR_IN_SECONDS', 365 * DAY_IN_SECONDS);

/**
* Retrieve the plural or single form based on the supplied amount.
*
* @param string \$single The text that will be used if \$number is 1.
* @param string \$plural The text that will be used if \$number is not 1.
* @param int    \$number The number to compare against to use either \$single or \$plural.
*
* @return string Either \$single or \$plural translated text.
*/
function _n(\$single, \$plural, \$number) {
return 1 === \$number ? \$single : \$plural;
}

/**
* Determines the difference between two timestamps.
*
* The difference is returned in a human readable format such as "1 hour",
* "5 mins", "2 days".
*
* @param int|string \$from Unix timestamp from which the difference begins.
* @param int|string \$to   Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
*
* @return string Human readable time difference.
*/
function human_time_diff(\$from, \$to = '') {
if (empty(\$to)) {
\$to = time();
}

\$diff = (int)abs(\$to - \$from);

if (\$diff < HOUR_IN_SECONDS) {
\$mins = round(\$diff / MINUTE_IN_SECONDS);
if (\$mins <= 1)
\$mins = 1;
/* translators: min=minute */
\$since = sprintf(_n('%s min', '%s mins', \$mins), \$mins);
}
elseif (\$diff < DAY_IN_SECONDS && \$diff >= HOUR_IN_SECONDS) {
\$hours = round(\$diff / HOUR_IN_SECONDS);
if (\$hours <= 1)
\$hours = 1;
\$since = sprintf(_n('%s hour', '%s hours', \$hours), \$hours);
}
elseif (\$diff < WEEK_IN_SECONDS && \$diff >= DAY_IN_SECONDS) {
\$days = round(\$diff / DAY_IN_SECONDS);
if (\$days <= 1)
\$days = 1;
\$since = sprintf(_n('%s day', '%s days', \$days), \$days);
}
elseif (\$diff < 30 * DAY_IN_SECONDS && \$diff >= WEEK_IN_SECONDS) {
\$weeks = round(\$diff / WEEK_IN_SECONDS);
if (\$weeks <= 1)
\$weeks = 1;
\$since = sprintf(_n('%s week', '%s weeks', \$weeks), \$weeks);
}
elseif (\$diff < YEAR_IN_SECONDS && \$diff >= 30 * DAY_IN_SECONDS) {
\$months = round(\$diff / (30 * DAY_IN_SECONDS));
if (\$months <= 1)
\$months = 1;
\$since = sprintf(_n('%s month', '%s months', \$months), \$months);
}
elseif (\$diff >= YEAR_IN_SECONDS) {
\$years = round(\$diff / YEAR_IN_SECONDS);
if (\$years <= 1)
\$years = 1;
\$since = sprintf(_n('%s year', '%s years', \$years), \$years);
}

if (\$to - \$from > 0) {
\$since = 'was ' . \$since . ' ago';
}
elseif (\$to - \$from < 0) {
\$since = 'will be in ' . \$since;
}

return \$since;

}
```

Try it using the output of `time()-9000` for "was 3 hours ago", or `time()+9000` for "will be in 3 hours".