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

open-hours

v1.0.0

Published

A lightweight library for parsing, querying, and displaying business hours

Readme

open-hours

A lightweight TypeScript library for parsing, querying, and displaying business hours. Handles complex cases like overnight hours, multiple time ranges per day, timezones, and holidays.

Features

  • Zero dependencies - Uses native Intl APIs for timezone and formatting
  • Lightweight - Under 5KB gzipped
  • Full TypeScript support - Complete type definitions included
  • Timezone aware - Correctly handles business hours across timezones
  • Edge case handling - Overnight hours, 24-hour businesses, holidays, temporary closures
  • Display helpers - Human-readable status text and formatted hours

Installation

npm install open-hours

Quick Start

import { OpenHours } from 'open-hours';

const hours = OpenHours.create({
  monday: [{ open: '09:00', close: '17:00' }],
  tuesday: [{ open: '09:00', close: '17:00' }],
  wednesday: [{ open: '09:00', close: '17:00' }],
  thursday: [{ open: '09:00', close: '17:00' }],
  friday: [{ open: '09:00', close: '17:00' }],
  saturday: 'closed',
  sunday: 'closed',
  timezone: 'America/Edmonton'
});

hours.isOpenNow();     // true/false
hours.status();        // 'open' | 'closed' | 'closes-soon' | 'opens-soon'
hours.statusText();    // "Open until 5:00 PM"
hours.todayHours();    // "9:00 AM - 5:00 PM"

API Reference

Creating an Instance

OpenHours.create(config, options?)

const hours = OpenHours.create({
  monday: [{ open: '09:00', close: '17:00' }],
  tuesday: [{ open: '09:00', close: '12:00' }, { open: '13:00', close: '17:00' }],
  friday: [{ open: '18:00', close: '02:00' }], // Overnight
  sunday: 'closed',
  timezone: 'America/Edmonton'
}, {
  soonThreshold: 30,  // Minutes for 'closes-soon'/'opens-soon' (default: 30)
  locale: 'en-US',    // Locale for formatting (default: 'en-US')
  use24Hour: false    // Use 24-hour time format (default: false)
});

OpenHours.fromGooglePlaces(data, options)

Parse Google Places API opening_hours format directly:

const hours = OpenHours.fromGooglePlaces(place.opening_hours, {
  timezone: 'America/Edmonton'
});

Query Methods

isOpenNow(): boolean

Check if the business is currently open.

hours.isOpenNow(); // true

isOpenAt(date: Date): boolean

Check if the business is open at a specific time.

hours.isOpenAt(new Date('2025-01-20T14:00:00')); // true

status(date?: Date): Status

Get the current status. Returns 'open', 'closed', 'closes-soon', or 'opens-soon'.

hours.status(); // 'open'

closesAt(date?: Date): Date | null

Get the next closing time. Returns null if currently closed.

hours.closesAt(); // Date object

opensAt(date?: Date): Date | null

Get the next opening time. Returns null if currently open.

hours.opensAt(); // Date object

nextOpen(date?: Date): Date | null

Get when the business next opens, regardless of current status.

hours.nextOpen(); // Date object

Time Calculations

closesIn(date?: Date): Duration | null

Get time remaining until closing.

hours.closesIn(); // { hours: 2, minutes: 30 }

opensIn(date?: Date): Duration | null

Get time remaining until opening.

hours.opensIn(); // { hours: 1, minutes: 15 }

Display Helpers

statusText(date?: Date): string

Get human-readable status text.

hours.statusText(); // "Open until 5:00 PM"
                    // "Closed, opens at 9:00 AM"
                    // "Closed, opens Monday at 9:00 AM"

todayHours(date?: Date): string

Get today's hours formatted for display.

hours.todayHours(); // "9:00 AM - 5:00 PM"
                    // "6:00 AM - 12:00 PM, 4:00 PM - 10:00 PM"
                    // "Closed"
                    // "24 Hours"

formatDay(day: DayName): string

Get formatted hours for a specific day.

hours.formatDay('monday'); // "9:00 AM - 5:00 PM"

formatWeek(): Record<DayName, string>

Get formatted hours for the entire week.

hours.formatWeek();
// {
//   sunday: 'Closed',
//   monday: '9:00 AM - 5:00 PM',
//   tuesday: '9:00 AM - 5:00 PM',
//   ...
// }

Serialization

toJSON(): OpenHoursConfig

Serialize back to a plain config object. Useful for storage or transmission.

const json = hours.toJSON();
localStorage.setItem('hours', JSON.stringify(json));

// Later...
const restored = OpenHours.create(JSON.parse(localStorage.getItem('hours')));

Advanced Usage

Multiple Time Ranges (Split Hours)

Handle restaurants with lunch breaks:

const restaurant = OpenHours.create({
  monday: [
    { open: '06:00', close: '12:00' },  // Breakfast/Lunch
    { open: '16:00', close: '22:00' }   // Dinner
  ],
  timezone: 'America/Edmonton'
});

restaurant.todayHours(); // "6:00 AM - 12:00 PM, 4:00 PM - 10:00 PM"
restaurant.isOpenAt(new Date('2025-01-20T14:00:00')); // false (during break)

Overnight Hours

Handle bars and nightclubs that close after midnight:

const bar = OpenHours.create({
  friday: [{ open: '18:00', close: '02:00' }],  // Closes 2 AM Saturday
  saturday: [{ open: '18:00', close: '02:00' }], // Closes 2 AM Sunday
  timezone: 'America/Edmonton'
});

// Saturday at 1 AM (still open from Friday)
bar.isOpenAt(new Date('2025-01-25T08:00:00Z')); // true

24-Hour Businesses

const store = OpenHours.create({
  monday: '24hours',
  tuesday: '24hours',
  // ...
  timezone: 'America/Edmonton'
});

Holidays

Support for both date-specific and recurring annual holidays:

const store = OpenHours.create({
  monday: [{ open: '09:00', close: '21:00' }],
  // ... other days
  timezone: 'America/Edmonton',
  holidays: [
    // Recurring holidays (MM-DD format)
    { date: '12-25', name: 'Christmas Day' },
    { date: '01-01', name: "New Year's Day" },

    // Date-specific (YYYY-MM-DD format)
    { date: '2025-07-01', name: 'Canada Day' },

    // Holiday with special hours
    {
      date: '12-24',
      name: 'Christmas Eve',
      ranges: [{ open: '09:00', close: '14:00' }]
    }
  ]
});

// Check Christmas
store.isOpenAt(new Date('2025-12-25T12:00:00')); // false
store.statusText(new Date('2025-12-25T12:00:00')); // "Closed for Christmas Day"

Temporary Closures

const store = OpenHours.create({
  monday: [{ open: '09:00', close: '17:00' }],
  // ...
  timezone: 'America/Edmonton',
  temporaryClosure: {
    start: '2025-02-01',
    end: '2025-02-15',
    reason: 'Renovations'
  }
});

store.statusText(new Date('2025-02-10T12:00:00'));
// "Temporarily closed: Renovations"

Timezone Handling

The library correctly handles timezone differences. A business in Calgary will show correct open/closed status regardless of where the user is:

// Business in Calgary (Mountain Time)
const calgaryBusiness = OpenHours.create({
  monday: [{ open: '09:00', close: '17:00' }],
  timezone: 'America/Edmonton'
});

// User checking from Toronto (Eastern Time)
// When it's 11 AM in Toronto, it's 9 AM in Calgary
const torontoTime = new Date('2025-01-20T16:00:00Z'); // 11 AM EST
calgaryBusiness.isOpenAt(torontoTime); // true (just opened in Calgary)

Types

import type {
  OpenHoursConfig,
  OpenHoursOptions,
  TimeRange,
  HolidayOverride,
  TemporaryClosure,
  DayName,
  DayInput,
  Status,
  Duration,
} from 'open-hours';

Browser Support

Works in all modern browsers and Node.js 18+. Requires Intl.DateTimeFormat support (available in all modern environments).

Development

# Install dependencies
npm install

# Run tests
npm test

# Build
npm run build

# Type check
npm run typecheck

License

MIT