Last active
April 26, 2020 06:19
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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