Security News
ESLint is Now Language-Agnostic: Linting JSON, Markdown, and Beyond
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
javascript-time-ago
Advanced tools
Intelligent, international, higly customizable relative date/time formatter (both for past and future dates).
The `javascript-time-ago` npm package is used to format dates and times in a human-readable way, such as '5 minutes ago' or '2 days ago'. It supports multiple languages and locales, making it a versatile tool for internationalization.
Basic Usage
This feature allows you to format a date into a human-readable string indicating the time elapsed since that date. The example shows how to set up the package for English and format a date to '1 minute ago'.
const TimeAgo = require('javascript-time-ago');
const en = require('javascript-time-ago/locale/en');
TimeAgo.addLocale(en);
const timeAgo = new TimeAgo('en-US');
console.log(timeAgo.format(new Date(Date.now() - 60 * 1000))); // '1 minute ago'
Custom Styles
This feature allows you to define custom styles for formatting the elapsed time. The example demonstrates how to create a custom style and use it to format a date.
const TimeAgo = require('javascript-time-ago');
const en = require('javascript-time-ago/locale/en');
TimeAgo.addLocale(en);
const timeAgo = new TimeAgo('en-US');
const customStyle = {
steps: [
{ formatAs: 'second' },
{ formatAs: 'minute' },
{ formatAs: 'hour' },
{ formatAs: 'day' },
{ formatAs: 'week' },
{ formatAs: 'month' },
{ formatAs: 'year' }
]
};
console.log(timeAgo.format(new Date(Date.now() - 60 * 1000), customStyle)); // '1 minute ago'
Localization
This feature supports multiple languages and locales, allowing you to format dates in different languages. The example shows how to set up the package for both English and Spanish.
const TimeAgo = require('javascript-time-ago');
const en = require('javascript-time-ago/locale/en');
const es = require('javascript-time-ago/locale/es');
TimeAgo.addLocale(en);
TimeAgo.addLocale(es);
const timeAgoEn = new TimeAgo('en-US');
const timeAgoEs = new TimeAgo('es-ES');
console.log(timeAgoEn.format(new Date(Date.now() - 60 * 1000))); // '1 minute ago'
console.log(timeAgoEs.format(new Date(Date.now() - 60 * 1000))); // 'hace 1 minuto'
Moment.js is a widely-used library for parsing, validating, manipulating, and formatting dates. It offers extensive functionality for date and time manipulation, but it is larger in size compared to `javascript-time-ago` and has been deprecated in favor of more modern solutions.
date-fns provides a comprehensive set of functions for working with dates in JavaScript. It is modular, allowing you to import only the functions you need, which can result in smaller bundle sizes. It also supports internationalization, similar to `javascript-time-ago`.
timeago.js is a small library used to format dates in a 'time ago' style. It is lightweight and easy to use, but it may not offer as many customization options or support for as many locales as `javascript-time-ago`.
Intelligent, international, higly customizable relative date/time formatter (both for past and future dates).
Automatically chooses the right units (seconds, minutes, etc) to format a time interval.
Examples:
For React users, there's a React component.
This is a readme for version 2.x
. For older versions, see version 1.x
readme. See a migration guide for migrating from version 1.x
to version 2.x
.
npm install javascript-time-ago --save
import TimeAgo from 'javascript-time-ago'
// Load locale-specific relative date/time formatting rules and labels.
import en from 'javascript-time-ago/locale/en'
// Add locale-specific relative date/time formatting rules and labels.
TimeAgo.addLocale(en)
// Create relative date/time formatter.
const timeAgo = new TimeAgo('en-US')
// Format relative date/time using "round" style.
timeAgo.format(new Date(), 'round')
// "just now"
timeAgo.format(Date.now() - 15 * 1000, 'round')
// "15 seconds ago"
timeAgo.format(Date.now() - 60 * 1000, 'round')
// "1 minute ago"
timeAgo.format(Date.now() - 2 * 60 * 60 * 1000, 'round')
// "2 hours ago"
timeAgo.format(Date.now() - 24 * 60 * 60 * 1000, 'round')
// "1 day ago"
This library includes date/time formatting rules and labels for any language.
No languages are loaded default: a developer must manually choose which languages should be loaded. The languages should be imported from javascript-time-ago/locale
and then added via TimeAgo.addLocale(...)
. An example of using Russian language:
import TimeAgo from 'javascript-time-ago'
// Load locale-specific relative date/time formatting rules and labels.
import en from 'javascript-time-ago/locale/en'
import ru from 'javascript-time-ago/locale/ru'
// Add locale-specific relative date/time formatting rules and labels.
// "en" is the default (fallback) locale.
// (that could be changed via `TimeAgo.setDefaultLocale(...)`)
TimeAgo.addLocale(en)
TimeAgo.addLocale(ru)
// cyka blyat
const timeAgo = new TimeAgo('ru-RU')
timeAgo.format(new Date(), 'round')
// "только что"
timeAgo.format(Date.now() - 15 * 1000, 'round')
// "15 секунд назад"
timeAgo.format(Date.now() - 60 * 1000, 'round')
// "1 минуту назад"
timeAgo.format(Date.now() - 2 * 60 * 60 * 1000, 'round')
// "2 часа назад"
timeAgo.format(Date.now() - 24 * 60 * 60 * 1000, 'round')
// "1 день назад"
This library allows for any custom logic for formatting time interval labels:
What scale should be used for measuring time intervals: should it be precise down to the second, or should it only measure it up to a minute, or should it start from being more precise when time intervals are small and then gradually decrease its precision as time intervals get larger.
What labels should be used: should it use the standard built-in labels for the languages ("... minutes ago"
, "... min. ago"
, "...m"
), or should it use custom ones, or should it skip using relative time labels in some cases and instead output something like "Dec 11, 2015"
.
Such configuration comes under the name of "style".
While a completely custom style could be supplied, this library comes with several built-in styles that some people might find useful.
Rounds the time up to the closest time measurement unit (second, minute, hour, etc).
timeAgo.format(Date.now(), 'round')
// 0 seconds ago → "just now"
timeAgo.format(Date.now() - 15 * 1000, 'round')
// 15 seconds ago → "15 seconds ago"
timeAgo.format(Date.now() - 1.5 * 60 * 1000, 'round')
// 1.5 minutes ago → "2 minutes ago"
Same as "round"
but without seconds.
timeAgo.format(Date.now(), 'round-minute')
// 0 seconds ago → "just now"
timeAgo.format(Date.now() - 15 * 1000, 'round-minute')
// 15 seconds ago → "just now"
timeAgo.format(Date.now() - 1.5 * 60 * 1000, 'round-minute')
// 1.5 minutes ago → "2 minutes ago"
"approximate"
style is a legacy one that has been introduced in the early versions of this library. It's the same as "round"
with the difference that it rounds time in some cases:
just now
→ just now
40 seconds ago
→ just now
45 seconds ago
→ 1 minute ago
5 minutes ago
→ 5 minutes ago
6 minutes ago
→ 5 minutes ago
7 minutes ago
→ 5 minutes ago
8 minutes ago
→ 10 minutes ago
9 minutes ago
→ 10 minutes ago
10 minutes ago
→ 10 minutes ago
timeAgo.format(Date.now(), 'approximate')
// 0 seconds ago → "just now"
timeAgo.format(Date.now() - 15 * 1000, 'approximate')
// 15 seconds ago → "just now"
timeAgo.format(Date.now() - 1.5 * 60 * 1000, 'approximate')
// 1.5 minutes ago → "2 minutes ago"
timeAgo.format(Date.now() - 3 * 60 * 1000, 'approximate')
// 3 minutes ago → "5 minutes ago"
For historical reasons, "approximate"
style is the one that's used when no style
argument is passed (this will be changed in the next major version: round
or round-minute
will be the default one).
"approximate-time"
style is a legacy one that has been introduced in the early versions of this library. It's the same as the "approximate"
but without the "ago" part.
timeAgo.format(Date.now(), 'approximate-time')
// 0 seconds ago → "just now"
timeAgo.format(Date.now() - 15 * 1000, 'approximate-time')
// 15 seconds ago → "just now"
timeAgo.format(Date.now() - 1.5 * 60 * 1000, 'approximate-time')
// 1.5 minutes ago → "2 minutes"
timeAgo.format(Date.now() - 3 * 60 * 1000, 'approximate-time')
// 3 minutes ago → "5 minutes"
Not all locales are applicable for this style: only those having long-time.json
.
Mimics Twitter style of "time ago" labels ("1s"
, "2m"
, "3h"
, "Mar 4"
, "Apr 5, 2012"
)
timeAgo.format(new Date(), 'twitter')
// 0 seconds ago → "0s"
timeAgo.format(new Date() - 1, 'twitter')
// 1 second ago → "1s"
timeAgo.format(Date.now() - 1.5 * 60 * 1000, 'twitter')
// 1.5 minutes ago → "2m"
timeAgo.format(Date.now() - 3.5 * 60 * 60 * 1000, 'twitter')
// 3.5 hours ago → "4h"
timeAgo.format(Date.now() - 4 * 24 * 60 * 60 * 1000, 'twitter')
// More than 24 hours ago → `month/day` ("Mar 4")
timeAgo.format(Date.now() - 364 * 24 * 60 * 60 * 1000, 'twitter')
// Another year → `month/day/year` ("Mar 5, 2017")
"twitter"
style uses Intl
for formatting day/month/year
labels. If Intl
is not available (for example, in Internet Explorer), it falls back to the default labels for month/year intervals: "1 mo. ago"
/"1 yr. ago"
.
Not all locales are applicable for this style: only those having mini-time.json
time labels.
This library comes with several built-in "styles", a "style" being an object defining labels
and steps
. A custom "style" object may be passed as a second parameter to .format(date, style)
function.
The time labels variant used for generating output. Is "long"
by default ("1 minute ago"
). Can be either a string, or an array of strings, in which case each one of them is tried until a supported one is found. For example, ["mini-time", "short"]
will search for "mini-time"
labels first and then fall back to "short"
labels if "mini-time"
labels aren't defined for the language. "long"
, "short"
and "narrow"
time labels are always present for each language. Other time label variants like "mini-time"
are only defined for a small subset of languages.
Relative date/time labels come in various styles: long
, short
, narrow
(these three are the standard CLDR ones that're always present), possibly accompanied by others like mini-time
("1m"
, "2h"
, ...). Refer to locale/en
for an example.
import english from 'javascript-time-ago/locale/en'
english['mini-time'] // '1s', '2m', '3h', '4d', …
english.narrow // '1 sec. ago', '2 min. ago', …
english.short // '1 sec. ago', '2 min. ago', …
english.long // '1 second ago', '2 minutes ago', …
mini-time
is supposed to be the shortest one possible. It's not a CLDR-defined one and has been defined only for a small subset of languages (en
, ru
, ko
, and several others).
narrow
is a CLDR-defined one and is intended to be shorter than short
, or at least no longer than it. I personally find narrow
a weird one because for some locales it's the same as short
and for other locales it's a really weird one (e.g. for Russian).
short
is "short".
long
is the normal one.
Time interval measurement "steps".
Each "step"'s threshold
(in seconds) is tested until the farthest eligible step is found, and that "step" is then used to generate output. If no eligible step
is found, then an empty string is returned.
"round"
style steps
example:
[
{
// "second" labels are used for formatting the output.
unit: 'second'
},
{
// "minute" labels are used for formatting the output.
unit: 'minute'
// This step is effective starting from 59.5 seconds.
threshold: 59.5
},
{
// "hour" labels are used for formatting the output.
unit: 'hour',
// This step is effective starting from 59.5 minutes.
threshold: 59.5 * 60
},
…
]
Each step is described by:
unit
— A time measurement unit the labels for which are used to generate the output of this step. If the unit
isn't supported by the language, then the step is ignored. The time units supported in all languages are: second
, minute
, hour
, day
, week
, quarter
, month
, year
. For some languages, this library also defines now
unit ("just now"
).threshold
— A minimum time interval (in seconds) required for this step, meaning that threshold
controls the progression from one step to another. Each step must have a threshold
defined, except for the first one. It can be a number
or a function(now: number, future: boolean): number
. In some advanced cases, like when using now
unit (which is only defined for a few languages), one could use a threshold_for_[unit]
override that would take priority over threshold
when the previous step's unit
is [unit]
(see "approximate"
steps for an example).It's also possible for a step to not just output a time interval in certain time units but instead return any custom output, in which case it should be defined using:
threshold
— Same as above.
format
— A function(value: Date/number, locale: string)
returning a string
. The value
argument is the date/time being formatted, as passed to timeAgo.format(value)
function: either a number
or a Date
. The locale
argument is the selected locale (aka "BCP 47 language tag", like "ru-RU"
). For example, "twitter"
style "steps" consists of generic second
, minute
and hour
steps, followed by a step with a format()
function that formats a date as "day/month/year"
(like Jan 24, 2018
).
Built-in steps
:
import { round, approximate } from 'javascript-time-ago/steps'
"approximate"
— These're, for historical reasons, the default steps
. Are used in ["approximate"
] style.
"round"
— Are used in ["round"
] style.
The /steps
export also provides some utility time unit values that can be used in threshold
s of custom steps
:
import { minute, hour, day, week, month, year } from 'javascript-time-ago/steps'
// in seconds
minute === 60
hour === 60 * 60
day === 24 * 60 * 60
...
When given future dates, .format()
produces the corresponding output, e.g. "in 5 minutes", "in a year", etc.
The default locale is en
and can be changed: TimeAgo.setDefaultLocale('ru')
.
This library uses a Intl.RelativeTimeFormat
polyfill under the hood.
There is also a React component built upon this library, that autorefreshes itself.
(this is an "advanced" section)
Intl
global object is not required for this library, but, for example, if you choose to use the built-in twitter
style then it will fall back to the default style if Intl
is not available.
Intl
is present in all modern web browsers and is absent from some of the old ones: Internet Explorer 10, Safari 9 and iOS Safari 9.x (which can be solved using Intl
polyfill).
Node.js starting from 0.12
has Intl
built-in, but only includes English locale data by default. If your app needs to support more locales than English on server side (e.g. Server-Side Rendering) then you'll need to use Intl
polyfill.
An example of applying Intl
polyfill:
npm install intl@1.2.4 --save
Node.js
import IntlPolyfill from 'intl'
const locales = ['en', 'ru', ...]
if (typeof Intl === 'object') {
if (!Intl.DateTimeFormat || Intl.DateTimeFormat.supportedLocalesOf(locales).length !== locales.length) {
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat
}
} else {
global.Intl = IntlPolyfill
}
Web browser: only download intl
package if the web browser doesn't support it, and only download the required locale.
async function initIntl() {
if (typeof Intl === 'object') {
return
}
await Promise.all([
import('intl'),
import('intl/locale-data/jsonp/en'),
import('intl/locale-data/jsonp/ru'),
...
])
}
initIntl().then(...)
FAQs
Localized relative date/time formatting
The npm package javascript-time-ago receives a total of 197,934 weekly downloads. As such, javascript-time-ago popularity was classified as popular.
We found that javascript-time-ago demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Security News
Members Hub is conducting large-scale campaigns to artificially boost Discord server metrics, undermining community trust and platform integrity.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.