ProvenPin Install

Luxon DateTime zones, durations and intervals: working versions (tested 2026-10-15)

Parse, convert and format with Luxon across zones, do calendar-aware math, business-hours checks and Interval overlap, all DST-safe.

passed5 passed · 0 failed2026-10-15 13:23 UTC
Status
passed
Last passed
2026-10-15 13:23 UTC
Tests
5 / 5
Language
TypeScript
Runtime
node v22.23.3
pinned versions4
luxon@3.7.2tsx@4.23.15@types/node@24.19.2@types/luxon@3.7.6
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38741369695

The code

Exactly the files that passed. Your agent can pull them with get_recipe("luxon-timezones-intervals") (install), or see them on GitHub.

package.json
{
  "name": "luxon-timezones-intervals",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "luxon": "3.7.2"
  },
  "devDependencies": {
    "tsx": "4.23.15",
    "@types/node": "24.19.2",
    "@types/luxon": "3.7.6"
  }
}
src/time.ts
import { DateTime, Interval, Duration, Settings } from "luxon";

Settings.throwOnInvalid = true; // fail loudly instead of producing Invalid DateTime

export const toZone = (iso: string, zone: string) => DateTime.fromISO(iso, { setZone: true }).setZone(zone);

export function isBusinessHours(isoUtc: string, zone: string) {
  const t = DateTime.fromISO(isoUtc, { zone: "utc" }).setZone(zone);
  return t.weekday <= 5 && t.hour >= 9 && t.hour < 17;
}

export const meetingsOverlap = (a: [string, string], b: [string, string]) =>
  Interval.fromISO(`${a[0]}/${a[1]}`).overlaps(Interval.fromISO(`${b[0]}/${b[1]}`));

export const humanDuration = (ms: number) => Duration.fromMillis(ms).shiftTo("hours", "minutes").toHuman({ unitDisplay: "short" });

export const addMonthsEndClamped = (iso: string, months: number) => DateTime.fromISO(iso, { zone: "utc" }).plus({ months }).toISODate();
test/time.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { DateTime } from "luxon";
import { addMonthsEndClamped, humanDuration, isBusinessHours, meetingsOverlap, toZone } from "../src/time.ts";

test("zone conversion keeps the instant", () => {
  const t = toZone("2026-07-01T12:00:00Z", "Europe/Paris");
  assert.equal(t.toFormat("HH:mm"), "14:00");
  assert.equal(t.offset, 120);
  assert.equal(t.toUTC().toISO(), "2026-07-01T12:00:00.000Z");
});

test("business hours in the caller's zone", () => {
  assert.equal(isBusinessHours("2026-10-15T17:00:00Z", "America/Anchorage"), true);  // 09:00 AKDT Thu
  assert.equal(isBusinessHours("2026-10-17T20:00:00Z", "America/Anchorage"), false); // Saturday
});

test("interval overlap", () => {
  assert.equal(meetingsOverlap(["2026-01-01T10:00Z", "2026-01-01T11:00Z"], ["2026-01-01T10:30Z", "2026-01-01T12:00Z"]), true);
  assert.equal(meetingsOverlap(["2026-01-01T10:00Z", "2026-01-01T11:00Z"], ["2026-01-01T11:00Z", "2026-01-01T12:00Z"]), false);
});

test("month math clamps to month end; durations read well", () => {
  assert.equal(addMonthsEndClamped("2026-01-31", 1), "2026-02-28");
  assert.match(humanDuration(5_400_000), /1 hr, 30 min/);
});

test("invalid input throws", () => {
  assert.throws(() => DateTime.fromISO("2026-13-45"));
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.