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

@sscovil/rtf

v1.0.0

Published

Relative time formatter that leverages Intl.RelativeTimeFormat() under the hood.

Downloads

7

Readme

RTF (Relative Time Format)

Easily convert any date to a relative time string (e.g., "yesterday", "last week", "2 years ago"), with translations for internationalization (i18n) and localization (l10n).

Key Features

  • Uses native JavaScript Intl.RelativeTimeFormat under the hood, with no dependencies.
  • Formats any Date object, timestamp, or valid string representation of a date that can be parsed by Date.parse().
  • Provides HTTP middleware compatible with popular REST frameworks like Express and i18n tools like i18next.

Why use this instead of Intl.RelativeTimeFormat.prototype.format()?

The API for Intl.RelativeTimeFormat.prototype.format() takes two arguments: value and units.

const rtf = new Intl.RelativeTimeFormat("en", { style: "narrow" });

expect(rtf.format(-1, "day")).toBe("1 day ago");
expect(rtf.format(10, "seconds")).toBe("in 10 sec.");

In order to convert a Date object, timestamp, or date string, you need to write a bunch of boilerplate. This library saves you that headache, and can also be used to generate a middleware function for your REST API that works with your i18n library.

Installation

yarn add @sscovil/rtf
# OR
npm install @sscovil/rtf

Usage

Format a Date object:

import RTF from "@sscovil/rtf";

const rtf = new RTF();
const date = new Date();
expect(rtf.format(date)).toBe("now");

const yesterday = new Date(date.getTime() - 24 * 60 * 60 * 1000);
expect(rtf.format(yesterday)).toBe("yesterday");

const tomorrow = new Date(date.getTime() + 24 * 60 * 61 * 1000);
expect(rtf.format(tomorrow)).toBe("tomorrow");

Format a numeric timestamp:

import RTF from "@sscovil/rtf";

const rtf = new RTF();
const date = Date.now();
expect(rtf.format(date)).toBe("now");

Format a date string:

import RTF from "@sscovil/rtf";

const rtf = new RTF();
const date = new Date().toUTCString();
expect(rtf.format(date)).toBe("now");

Format in another language:

import RTF from "@sscovil/rtf";

const rtf = new RTF();
const minutesAgo = Date.now() - 30 * 60 * 1000;
expect(rtf.format(minutesAgo, "en")).toBe("30 minutes ago");
expect(rtf.format(minutesAgo, "es")).toBe("hace 30 minutos");
expect(rtf.format(minutesAgo, "ja")).toBe("30 分前");
expect(rtf.format(minutesAgo, "ru")).toBe("30 минут назад");
expect(rtf.format(minutesAgo, "zh")).toBe("30分钟前");

Use different Intl.RelativeTimeFormat options:

import RTF from "@sscovil/rtf";

const rtf = new RTF({
    localeMatcher: RTF.opt.localeMatcher.lookup,
    numeric: RTF.opt.numeric.always,
    style: RTF.opt.style.short
});
const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
expect(rtf.format(weekAgo)).toBe("1 wk. ago");

Use as Express middleware in conjunction with i18next:

import express from "express";
import i18next from "i18next";
import i18nextMiddleware from "i18next-http-middleware";
import RTF from "@sscovil/rtf";

const app = express();

i18next.use(i18nextMiddleware.LanguageDetector).init({ /* i18next config */ });
app.use(i18nextMiddleware.handle(i18next));
app.use(RTF.httpMiddleware()); // with default configuration

app.get("/", (req, res) => {
    const minutesAgo = Date.now() - 30 * 60 * 1000;
    expect(req.language).toBe("en"); // or whatever language was detected by i18nextMiddleware.LanguageDetector
    expect(req.rtf(minutesAgo)).toBe("30 minutes ago"); // by default, req.rtf function uses req.language for locale
});

Use as Express middleware with another i18n language detector:

import express from "express";
import RTF from "@sscovil/rtf";

const app = express();

app.use((req, res, next) => {
    req.locale = req.query.lng; // basic i18n middleware to detect language from a query parameter, for example
    next();
});

const rtf = new RTF({ style: RTF.opt.style.short });

app.use(RTF.httpMiddleware(rtf, "rtFormat", "locale")); // with custom configuration

app.get("/", (req, res) => {
    const minutesAgo = Date.now() - 30 * 60 * 1000;
    expect(req.locale).toBe("en"); // or whatever language was detected by the custom i18n middleware defined above
    expect(req.rtFormat(minutesAgo)).toBe("30 min. ago"); // req.rtFormat function uses req.locale, based on config
});

Running Tests

yarn run test
# OR
npm test