2021 version
Inspired with Alnitak's and RienNeVaPlus's answers.
Calculates since and until automatically (see examples below).
const timeUnits = {
year: 31536e6,
month: 2592e6,
week: 6048e5,
day: 864e5,
hour: 36e5,
minute: 6e4,
second: 1e3,
};
const timeUnitsNamesShort = {
year: 'y',
month: 'm',
week: 'w',
day: 'd',
hour: 'h',
minute: 'm',
second: 's',
};
const isFuture = (date) => date > Date.now();
const dateDiffStructure = (date, units = timeUnits) => {
let delta = Math.abs(date - Date.now());
return Object.entries(units).reduce((acc, [key, value]) => {
acc[key] = Math.floor(delta / value);
delta -= acc[key] * value;
return acc;
}, {});
};
const dateDiffStructureToString = (date, diffStructure, values, short) => {
const diffStructureEntries = values
? Object.entries(diffStructure).filter(([key, value]) => values.includes(key) && value)
: Object.entries(diffStructure).filter(([, value]) => value);
if (!diffStructureEntries.length) return 'just now';
const suffix = isFuture(date) ? 'left' : 'ago';
const diffString = diffStructureEntries.reduce((acc, [key, value]) => {
const timeUnit = short
? timeUnitsNamesShort[key]
: value > 1
? ` ${key}s`
: ` ${key}`;
acc = acc ? `${acc} ` : '';
return `${acc}${value}${timeUnit}`;
}, '');
return `${diffString} ${suffix}`;
};
const getDateDiff = (date, values, short) => {
const diffStructure = dateDiffStructure(date);
return dateDiffStructureToString(date, diffStructure, values, short);
};
Tests and examples:
const timeUnits = {
year: 31536e6,
month: 2592e6,
week: 6048e5,
day: 864e5,
hour: 36e5,
minute: 6e4,
second: 1e3,
};
const timeUnitsNamesShort = {
year: 'y',
month: 'm',
week: 'w',
day: 'd',
hour: 'h',
minute: 'm',
second: 's',
};
const isFuture = (date) => date > Date.now();
const dateDiffStructure = (date, units = timeUnits) => {
let delta = Math.abs(date - Date.now());
return Object.entries(units).reduce((acc, [key, value]) => {
acc[key] = Math.floor(delta / value);
delta -= acc[key] * value;
return acc;
}, {});
};
const dateDiffStructureToString = (date, diffStructure, values, short) => {
const diffStructureEntries = values ?
Object.entries(diffStructure).filter(([key, value]) => values.includes(key) && value) :
Object.entries(diffStructure).filter(([, value]) => value);
if (!diffStructureEntries.length) return 'just now';
const suffix = isFuture(date) ? 'left' : 'ago';
const diffString = diffStructureEntries.reduce((acc, [key, value]) => {
const timeUnit = short ?
timeUnitsNamesShort[key] :
value > 1 ?
` ${key}s` :
` ${key}`;
acc = acc ? `${acc} ` : '';
return `${acc}${value}${timeUnit}`;
}, '');
return `${diffString} ${suffix}`;
};
const getDateDiff = (date, values, short) => {
const diffStructure = dateDiffStructure(date);
console.log(`dateDiffStructure(${JSON.stringify(date)}) //`, diffStructure);
return dateDiffStructureToString(date, diffStructure, values, short);
};
const tests = [
['After tomorrow', [new Date(Date.now() + 8.64e7 + 1e6)]],
['Yesterday', [new Date(Date.now() - 8.64e7)]],
['Past', [new Date(Date.now() * Math.random())]],
['Future short', [new Date(Date.now() * (Math.random() + 1)), ['year', 'month', 'day'], true]],
['Now', [Date.now()]]
];
tests.forEach(([text, args]) => {
console.log(`${text}:`);
console.group();
console.log(`getDateDiff(${args.map(item => JSON.stringify(item)).join(', ')}) //`, getDateDiff(...args));
console.groupEnd();
});