npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

relative-time-format

v1.1.6

Published

A convenient Intl.RelativeTimeFormat polyfill

Downloads

1,919,898

Readme

relative-time-format

npm version npm downloads npm size coverage

This library consists of three parts:

See Demo

Install

npm install relative-time-format --save

If you're not using a bundler then use a standalone version from a CDN.

Use

import RelativeTimeFormat from "relative-time-format"
import en from "relative-time-format/locale/en"

RelativeTimeFormat.addLocale(en)

// Returns "2 days ago"
new RelativeTimeFormat("en", {
  style: "long" // "long" is the default. Other options: "short", "narrow".
}).format(-2, "day")

Locales

The localization resides in the locale folder. The format of a localization is:

{
  …
  "day": {
    "past": {
      "one": "{0} day ago",
      "other": "{0} days ago"
    },
    "future": {
      "one": "in {0} day",
      "other": "in {0} days"
    }
  },
  …
}

The past and future can be defined by any of: zero, one, two, few, many and other. For more info on which is which read the official Unicode CLDR documentation. Unicode CLDR (Common Locale Data Repository) is an industry standard and is basically a collection of formatting rules for all locales (date, time, currency, measurement units, numbers, etc). All localizations come from cldr-dates-full package (for example, en-US).

To determine whether a certain amount of time (number) is one, few, or something else, relative-time-format uses Unicode CLDR rules for formatting plurals. These rules are number quantifying functions (one for each locale) which can tell if a number should be treated as zero, one, two, few, many or other. Knowing how these pluralization rules work is not required but anyway here are some links for curious advanced readers: rules explanation, list of rules for all locales, list of rules for all locales in JSON format (part of cldr-core/supplemental package), converting those rules to javascript functions. These quantifying functions can be found as quantify properties of a locale data.

The locale folder is generated from CLDR data by running:

npm run generate-locales

Locale data is extracted from cldr-core (quantifiers) and cldr-dates-full (relative time messages) packages which usually get some updates once or twice a year.

npm run update-locales

Higher-level API

Intl.RelativeTimeFormat is intentionally a low-level API. Third-party libraries are supposed to be built on top of this base-level API. An example of such library is javascript-time-ago which uses Intl.RelativeTimeFormat internally and provides a higher-level API:

import TimeAgo from 'javascript-time-ago'

// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'

// Add locale-specific relative date/time formatting rules.
TimeAgo.addLocale(en)

// Create relative date/time formatter.
const timeAgo = new TimeAgo('en-US')

timeAgo.format(new Date())
// "just now"

timeAgo.format(Date.now() - 60 * 1000)
// "a minute ago"

timeAgo.format(Date.now() - 2 * 60 * 60 * 1000)
// "2 hours ago"

timeAgo.format(Date.now() - 24 * 60 * 60 * 1000)
// "a day ago"

CDN

One can use any npm CDN service, e.g. unpkg.com or jsdelivr.net

<script src="https://unpkg.com/relative-time-format@[version]/bundle/polyfill.js"></script>

<script>
  var en = ... // Somehow import `relative-time-format/locale/en`.
  RelativeTimeFormat.addLocale(en)
  console.log(new RelativeTimeFormat('en').format(-1, 'days'))
</script>

where [version] is an npm package version range (for example, 0.2.x or ^0.2.0).

Test262

There's a test suite of about 150 test cases for Intl.RelativeTimeFormat specification implementations. It's called "Test262". These tests check every possible imaginable aspect of formal correctness of a spec implementation including the weirdest artificial cases imaginable like accepting strings instead of numbers, accepting objects having keys 0, 1, etc instead of arrays, accepting objects with toString() method instead of strings, defining all class methods as special "non-enumerable" properties via Object.defineProperty() instead of the regular way everyone defines class methods in real life, and so on. Handling all these formal edge cases would result in an unnecessarily convoluted and less readable code and I'd prefer to keep things simple and elegant, so this library intentionally chose not to pass all of the "Test262" test cases while still passing most of them: it passes the functional correctness part and skips the not-relevant-in-real-life cases part.

Tests

This component comes with a 100% code coverage.

To run tests:

npm test

To generate a code coverage report:

npm run test-coverage

The code coverage report can be viewed by opening ./coverage/lcov-report/index.html.

The [email protected] workaround in devDependencies is for the test coverage to not produce empty reports:

Handlebars: Access has been denied to resolve the property "statements" because it is not an "own property" of its parent.
You can add a runtime option to disable the check or this warning:
See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details

TypeScript

This library comes with TypeScript "typings". If you happen to find any bugs in those, create an issue.

License

MIT