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 🙏

© 2026 – Pkg Stats / Ryan Hefner

tz-clock

v0.2.1

Published

Project moments into IANA timezones — get wall-clock fields, offset, formatted output. Built on Intl, zero dependencies.

Readme

tz-clock

ci

npm downloads bundle

Project moments into IANA timezones — wall-clock fields, UTC offset, formatted output. Built on the Intl APIs already in your runtime. Zero dependencies. No 7MB tzdata bundle, no plugins, no temporal polyfills.

import { at, now, format, offsetMinutes } from "tz-clock";

now("Europe/Bucharest");
// {
//   year: 2026, month: 5, day: 19,
//   hour: 15, minute: 0, second: 0,
//   weekday: 2,             // Tuesday
//   offsetMinutes: 180,     // +03:00 (DST)
//   iso: "2026-05-19T15:00:00+03:00"
// }

format(Date.now(), "Asia/Tokyo", { dateStyle: "long", timeStyle: "short" });
// "May 19, 2026, 9:00 PM"

offsetMinutes("America/Los_Angeles");  // -420 in summer (PDT), -480 in winter (PST)

Install

npm install tz-clock

Works with Node 20+, browsers, Bun, Deno. ESM + CJS.

Why

Day.js + tz plugin: ~7KB minified. Moment-timezone: ~30KB. date-fns-tz: ~5KB. All ship their own tzdata.

tz-clock does this in ~150 lines because your runtime already has tzdata. Intl.DateTimeFormat knows every IANA zone and handles DST correctly. The hard part is extracting structured fields out of Intl's rendered output — that's what this package does.

Recipes

"What time is it in our user's timezone?"

import { format } from "tz-clock";

const greeting = `Good morning, it's ${format(Date.now(), user.timezone, {
  hour: "2-digit",
  minute: "2-digit",
  hour12: false,
})}`;

Meeting times across team members

import { format } from "tz-clock";

function meetingTimes(meetingUtc: Date, timezones: string[]) {
  return timezones.map((tz) => ({
    tz,
    local: format(meetingUtc, tz, { weekday: "short", hour: "numeric", minute: "2-digit" }),
  }));
}

meetingTimes(new Date("2026-05-20T15:00:00Z"), [
  "America/Los_Angeles",
  "Europe/London",
  "Asia/Singapore",
]);
// [
//   { tz: "America/Los_Angeles", local: "Wed, 8:00 AM" },
//   { tz: "Europe/London",       local: "Wed, 4:00 PM" },
//   { tz: "Asia/Singapore",      local: "Wed, 11:00 PM" },
// ]

Schedule a job at 9am in a specific zone

import { at, offsetMinutes } from "tz-clock";

function nextNineAm(tz: string): Date {
  const z = at(Date.now(), tz);
  const localNineUtc = Date.UTC(z.year, z.month - 1, z.day, 9) - z.offsetMinutes * 60_000;
  if (localNineUtc <= Date.now()) return new Date(localNineUtc + 86_400_000);
  return new Date(localNineUtc);
}

Detect DST transitions

import { offsetMinutes } from "tz-clock";

const summer = offsetMinutes("Europe/Berlin", new Date("2026-07-01Z"));  // 120
const winter = offsetMinutes("Europe/Berlin", new Date("2026-01-01Z"));  // 60
console.log(`DST shift: ${summer - winter} minutes`);  // 60

API

at(date, tz): ZonedTime

type ZonedTime = {
  year: number;
  month: number;       // 1..12
  day: number;
  hour: number;        // 0..23
  minute: number;
  second: number;
  weekday: number;     // 0 = Sunday ... 6 = Saturday
  offsetMinutes: number;
  iso: string;         // ISO-8601 with offset
};

date is a Date or unix-ms number. Throws on unknown timezone.

now(tz): ZonedTime

Sugar for at(new Date(), tz).

format(date, tz, opts?): string

Delegates to Intl.DateTimeFormat. Pass any Intl.DateTimeFormatOptions field (plus locale).

offsetMinutes(tz, date?): number

Returns the zone's UTC offset, in minutes, at the given instant. Handles DST correctly.

offsetMinutes("UTC");                    //    0
offsetMinutes("Europe/Bucharest");       //  180 in summer, 120 in winter
offsetMinutes("America/Los_Angeles");    // -420 in summer, -480 in winter
offsetMinutes("Asia/Kolkata");           //  330 (no DST)

listZones(): string[]

Returns the runtime's known IANA zones via Intl.supportedValuesOf("timeZone"). Throws on older runtimes that don't support it.

Conversion patterns

tz-clock gives you wall-clock fields for a given zone. To construct a UTC Date from "9am in Bucharest", do the math yourself:

import { offsetMinutes } from "tz-clock";

const localNineAm = new Date(2026, 4, 19, 9);
const off = offsetMinutes("Europe/Bucharest", localNineAm);
const bucharestNineAmUtc = new Date(Date.UTC(2026, 4, 19, 9) - off * 60_000);

This is intentionally manual — adding a fromZoned() helper would require dealing with DST-transition ambiguity (the "spring forward" hour doesn't exist; the "fall back" hour exists twice) which is library-territory complexity.

Caveats

  • Pre-1970 dates may be inaccurate for some zones — depends on the host's ICU/CLDR data.
  • No reverse conversion for now — see "Conversion patterns" above.
  • Output strings depend on Node/ICU version. Don't snapshot them in tests across runtimes; use the structured at() fields instead.

License

Apache-2.0 © Vlad Bordei