Skip to main content

Convert seconds or Date objects into human-readable relative time strings

This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
This package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
This package works with Browsers
JSR Score
100%
Published
8 months ago (1.0.0)

Human-Readable Timestamp

A utility to convert seconds or a Date object into a human-readable relative time string.

Table of Contents

Introduction

This utility provides a function to transform seconds or Date objects into human-readable relative time strings, such as "3 hours ago" or "2 days from now". It is highly customizable, allowing for various formatting and localization options.

Installation

To install the package, you can use any of the commands below:

npx jsr add @blaze/human-readable-timestamp
# or
yarn dlx jsr add @blaze/human-readable-timestamp
# or
pnpm dlx jsr add @blaze/human-readable-timestamp
# or
bunx jsr add @blaze/human-readable-timestamp

Usage

import { humanReadableTimestamp } from "@blaze/human-readable-timestamp";

// Example usage with default options
const timestamp = humanReadableTimestamp(new Date(Date.now() - 3600 * 1000)); // "1 hour ago"
console.log(timestamp);

Options

The humanReadableTimestamp function accepts two parameters:

  1. input: A number representing seconds or a Date object.
  2. options: An optional configuration object to customize the output.

Configuration Options

  • maxUnits (number): Maximum number of time units to display. Default is 1.
  • pastSuffix (string): Suffix for past times. Default is "ago".
  • futureSuffix (string): Suffix for future times. Default is "from now".
  • localize (boolean): Whether to localize the output string. Default is false.
  • verbose (boolean): Whether to use verbose mode (e.g., "about 3 hours"). Default is false.
  • customUnits (Partial<Record<TimeUnit, string>>): Custom time unit labels.
  • thresholds (Partial<Record<TimeUnit, number>>): Custom thresholds for switching units.
  • abbreviate (boolean): Whether to use abbreviated unit labels (e.g., "hr" instead of "hour"). Default is false.
  • customFormatter (function): Custom function to format the output string.

Features

  • Relative Time Calculation: Convert seconds or Date objects into relative time strings.
  • Customization: Customize the output with various options such as unit labels, thresholds, suffixes, and localization.
  • Abbreviation: Option to abbreviate unit labels.
  • Verbose Mode: Option for verbose output.

Dependencies

This utility does not have any external dependencies.

Tests

The module includes a comprehensive test suite to ensure functionality and reliability.

Test Setup

To run the tests, you will need to have a testing framework installed, such as Deno.

Test Cases

Below are examples of the test cases included in the test suite:

import { assertEquals } from "jsr:@std/assert";
import { describe, it } from "jsr:@std/testing/bdd";
import { humanReadableTimestamp } from "./mod.ts";

describe("humanReadableTimestamp", () => {
  it("handles basic cases", () => {
    assertEquals(humanReadableTimestamp(30), "30 seconds ago");
    assertEquals(humanReadableTimestamp(60), "1 minute ago");
    assertEquals(humanReadableTimestamp(3600), "1 hour ago");
    assertEquals(humanReadableTimestamp(86400), "1 day ago");
    assertEquals(humanReadableTimestamp(604800), "1 week ago");
    assertEquals(humanReadableTimestamp(2592000), "1 month ago");
    assertEquals(humanReadableTimestamp(31536000), "1 year ago");
  });

  it("handles future timestamps", () => {
    assertEquals(humanReadableTimestamp(-30), "30 seconds from now");
    assertEquals(humanReadableTimestamp(-3600), "1 hour from now");
  });

  it("handles multiple units", () => {
    assertEquals(
      humanReadableTimestamp(3661, { maxUnits: 2 }),
      "1 hour, 1 minute ago"
    );
    assertEquals(
      humanReadableTimestamp(3661, { maxUnits: 3 }),
      "1 hour, 1 minute, 1 second ago"
    );
  });

  it("respects maxUnits option", () => {
    assertEquals(humanReadableTimestamp(3661, { maxUnits: 1 }), "1 hour ago");
    assertEquals(
      humanReadableTimestamp(3661, { maxUnits: 2 }),
      "1 hour, 1 minute ago"
    );
  });

  it("handles custom suffixes", () => {
    assertEquals(
      humanReadableTimestamp(60, { pastSuffix: "in the past" }),
      "1 minute in the past"
    );
    assertEquals(
      humanReadableTimestamp(-60, { futureSuffix: "in the future" }),
      "1 minute in the future"
    );
  });

  it("handles localization", () => {
    assertEquals(
      humanReadableTimestamp(1500, { localize: true }),
      "25 minutes ago"
    );
    // Note: This test might fail in different locales
  });

  it("handles verbose mode", () => {
    assertEquals(
      humanReadableTimestamp(60, { verbose: true }),
      "about 1 minute ago"
    );
  });

  it("handles custom units", () => {
    assertEquals(
      humanReadableTimestamp(60, { customUnits: { minute: "min" } }),
      "1 min ago"
    );
  });

  it("handles custom thresholds", () => {
    assertEquals(
      humanReadableTimestamp(44, { thresholds: { minute: 0.75 } }),
      "44 seconds ago"
    );

    assertEquals(
      humanReadableTimestamp(45, { thresholds: { minute: 0.75 } }),
      "1 minute ago"
    );
  });

  it("handles abbreviations", () => {
    assertEquals(
      humanReadableTimestamp(3661, { abbreviate: true, maxUnits: 2 }),
      "1 hr, 1 min ago"
    );
  });

  it("handles custom formatter", () => {
    const customFormatter = (units: string[], suffix: string) =>
      `It's been ${units.join(" and ")} ${suffix}`;
    assertEquals(
      humanReadableTimestamp(3661, {
        maxUnits: 2,
        customFormatter,
      }),
      "It's been 1 hour and 1 minute ago"
    );
  });

  it("handles Date objects", () => {
    const now = new Date();
    const oneHourAgo = new Date(now.getTime() - 3600000);
    assertEquals(humanReadableTimestamp(oneHourAgo), "1 hour ago");
  });

  it("throws error for invalid input", () => {
    try {
      humanReadableTimestamp("invalid" as unknown as number);
      throw new Error("Should have thrown an error");
    } catch (error) {
      assertEquals(
        error.message,
        "Invalid input: input must be a number representing seconds or a Date object."
      );
    }
  });

  it("handles zero seconds", () => {
    assertEquals(humanReadableTimestamp(0), "0 seconds ago");
  });

  it("handles very large numbers", () => {
    assertEquals(humanReadableTimestamp(1e10), "317 years ago");
  });
});

Contributors

  • Sabry Awad - Initial work

License

This project is licensed under the MIT License. See the LICENSE file for details.

Add Package

deno add jsr:@blaze/human-readable-timestamp

Import symbol

import * as human_readable_timestamp from "@blaze/human-readable-timestamp";

---- OR ----

Import directly with a jsr specifier

import * as human_readable_timestamp from "jsr:@blaze/human-readable-timestamp";

Add Package

npx jsr add @blaze/human-readable-timestamp

Import symbol

import * as human_readable_timestamp from "@blaze/human-readable-timestamp";

Add Package

yarn dlx jsr add @blaze/human-readable-timestamp

Import symbol

import * as human_readable_timestamp from "@blaze/human-readable-timestamp";

Add Package

pnpm dlx jsr add @blaze/human-readable-timestamp

Import symbol

import * as human_readable_timestamp from "@blaze/human-readable-timestamp";

Add Package

bunx jsr add @blaze/human-readable-timestamp

Import symbol

import * as human_readable_timestamp from "@blaze/human-readable-timestamp";