Nutrient Packed Morsels


    1.0.0 • Public • Published

    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.


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


    Format a Date object:

    import RTF from "@sscovil/rtf";
    const rtf = new RTF();
    const date = new Date();
    const yesterday = new Date(date.getTime() - 24 * 60 * 60 * 1000);
    const tomorrow = new Date(date.getTime() + 24 * 60 * 61 * 1000);

    Format a numeric timestamp:

    import RTF from "@sscovil/rtf";
    const rtf = new RTF();
    const date =;

    Format a date string:

    import RTF from "@sscovil/rtf";
    const rtf = new RTF();
    const date = new Date().toUTCString();

    Format in another language:

    import RTF from "@sscovil/rtf";
    const rtf = new RTF();
    const minutesAgo = - 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,
    const weekAgo = - 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(RTF.httpMiddleware()); // with default configuration
    app.get("/", (req, res) => {
        const minutesAgo = - 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
    const rtf = new RTF({ style: });
    app.use(RTF.httpMiddleware(rtf, "rtFormat", "locale")); // with custom configuration
    app.get("/", (req, res) => {
        const minutesAgo = - 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


    npm i @sscovil/rtf

    DownloadsWeekly Downloads






    Unpacked Size

    19.1 kB

    Total Files


    Last publish


    • sscovil