Skip to content

Instantly share code, notes, and snippets.

@themojilla
Last active April 26, 2020 06:19
Show Gist options
  • Save themojilla/db4e22364fcc6bd0f1b20fdf9ea2f002 to your computer and use it in GitHub Desktop.
Save themojilla/db4e22364fcc6bd0f1b20fdf9ea2f002 to your computer and use it in GitHub Desktop.
A utility helper to calculate "time ago" or "from now " in a readable format using Intl API
// Order does matter
const units = [
['second', 1],
['minute', 60],
['hour', 60 * 60],
['day', 24 * 60 * 60],
['month', 30 * 24 * 60 * 60],
['year', 12 * 30 * 24 * 60 * 60],
];
export function diffUnitFor(from) {
const delta = Math.round((from - Date.now()) / 1000); // Rounded delta in seconds
for (let i = 0; i < units.length; i += 1) {
if (Math.abs(delta) < units[i][1]) {
const [unit, value] = units[i - 1];
// Exit the function once a unit will be found
return { unit, delta: Math.round(delta / value) };
}
}
return {
delta: Math.round(delta / (12 * 30 * 24 * 60 * 60)),
unit: 'year'
};
}
/**
* Calculate "time ago" or "from now" in a readable format using Intl API
*
* @param {Date|String} date
* @param {String} lang
* @returns {String}
*/
export default function fromNow(date, lang = 'en') {
let from = date;
if (!date) {
return '';
}
if (!(date instanceof Date)) {
from = new Date(date);
if (isNaN(from.getTime())) {
return '';
}
}
const rtf1 = new Intl.RelativeTimeFormat(lang, { style: 'long' });
const { delta, unit } = diffUnitFor(from);
return rtf1.format(delta, unit);
}
// assertions
const originalNowUtil = Date.now;
describe('utils/fromNow', () => {
beforeAll(() => {
/* eslint-disable global-require */
const RelativeTimeFormat = require('relative-time-format').default;
RelativeTimeFormat
.addLocale(require('relative-time-format/locale/en.json'));
RelativeTimeFormat
.addLocale(require('relative-time-format/locale/fa.json'));
global.Intl.RelativeTimeFormat = RelativeTimeFormat;
global.Date.now = jest
.fn(() => new Date('2020-04-20T10:20:30Z').getTime());
});
describe('#fromNow', () => {
it('should return time ago for given time string', () => {
expect(fromNow('2017-07-10T12:24:01Z')).toBe('3 years ago');
expect(fromNow('2020-04-20T10:20:00Z')).toBe('30 seconds ago');
expect(fromNow('2020-03-20T10:20:00Z')).toBe('1 month ago');
expect(fromNow('2020-04-20T10:19:00Z')).toBe('1 minute ago');
expect(fromNow('2020-04-19T10:19:00Z')).toBe('1 day ago');
expect(fromNow('2020-04-20T10:15:00Z')).toBe('5 minutes ago');
});
it('should return time ago for given time string and lang', () => {
expect(fromNow('2017-07-10T12:24:01Z', 'fa')).toBe('3 سال پیش');
expect(fromNow('2020-04-20T10:15:00Z', 'fa')).toBe('5 دقیقه پیش');
});
it('should return empty string if date is not provided', () => {
expect(fromNow('')).toBe('');
});
it('should return empty string if date is invalid', () => {
expect(fromNow('dummy input')).toBe('');
});
});
afterAll(() => {
global.Date.now = originalNowUtil;
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment