ProvenPin Install

moment-timezone convert and format: working versions (tested 2026-10-18)

Parse wall times in America/New_York, convert to Asia/Tokyo and UTC, format zone abbreviations, handle the spring forward gap and fall back overlap, and compute business-hour overlap between zones offline.

passed4 passed · 0 failed2026-10-18 03:58 UTC
Status
passed
Last passed
2026-10-18 03:58 UTC
Tests
4 / 4
Language
TypeScript
Runtime
node v22.23.3
pinned versions4
moment@2.31.0moment-timezone@0.6.5@types/node@26.6.5tsx@4.23.15
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 39095442401

The code

Exactly the files that passed. Your agent can pull them with get_recipe("moment-timezone-convert-format") (install), or see them on GitHub.

package.json
{
  "name": "moment-timezone-convert-format",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "moment": "2.31.0",
    "moment-timezone": "0.6.5"
  },
  "devDependencies": {
    "@types/node": "26.6.5",
    "tsx": "4.23.15"
  }
}
src/timezone.ts
import moment from "moment-timezone";

export type Interval = { startMs: number; endMs: number };

export function parseLocal(input: string, zone: string): moment.Moment {
  return moment.tz(input, "YYYY-MM-DD HH:mm", zone);
}

export function fromUtcInstant(iso: string): moment.Moment {
  return moment.utc(iso);
}

export function toZone(m: moment.Moment, zone: string): moment.Moment {
  return m.clone().tz(zone);
}

export function formatWithZoneAbbrev(m: moment.Moment, zone: string): string {
  return m.clone().tz(zone).format("YYYY-MM-DD HH:mm z");
}

export function utcIso(m: moment.Moment): string {
  return m.clone().utc().toISOString();
}

export function businessInterval(
  dateYmd: string,
  zone: string,
  openHour: number,
  closeHour: number
): Interval {
  const start = moment.tz(`${dateYmd} ${pad2(openHour)}:00`, "YYYY-MM-DD HH:mm", zone);
  const end = moment.tz(`${dateYmd} ${pad2(closeHour)}:00`, "YYYY-MM-DD HH:mm", zone);
  return { startMs: start.valueOf(), endMs: end.valueOf() };
}

export function overlapHours(a: Interval, b: Interval): number {
  const start = Math.max(a.startMs, b.startMs);
  const end = Math.min(a.endMs, b.endMs);
  return end > start ? (end - start) / 3600000 : 0;
}

function pad2(n: number): string {
  return String(n).padStart(2, "0");
}
test/timezone.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import {
  parseLocal,
  fromUtcInstant,
  toZone,
  formatWithZoneAbbrev,
  utcIso,
  businessInterval,
  overlapHours,
} from "../src/timezone.ts";

test("converts a New York morning to Tokyo and UTC with abbreviations", () => {
  const ny = parseLocal("2024-07-01 09:00", "America/New_York");
  assert.equal(formatWithZoneAbbrev(ny, "America/New_York"), "2024-07-01 09:00 EDT");
  assert.equal(formatWithZoneAbbrev(ny, "Asia/Tokyo"), "2024-07-01 22:00 JST");
  assert.equal(formatWithZoneAbbrev(ny, "UTC"), "2024-07-01 13:00 UTC");
  assert.equal(utcIso(ny), "2024-07-01T13:00:00.000Z");
});

test("spring forward gap normalizes 02:30 to 03:30 EDT", () => {
  const gap = parseLocal("2024-03-10 02:30", "America/New_York");
  assert.equal(formatWithZoneAbbrev(gap, "America/New_York"), "2024-03-10 03:30 EDT");
  assert.equal(formatWithZoneAbbrev(gap, "Asia/Tokyo"), "2024-03-10 16:30 JST");
  assert.equal(utcIso(gap), "2024-03-10T07:30:00.000Z");
});

test("fall back overlap maps two UTC instants to 01:30 local", () => {
  const first = parseLocal("2024-11-03 01:30", "America/New_York");
  assert.equal(formatWithZoneAbbrev(first, "America/New_York"), "2024-11-03 01:30 EDT");
  assert.equal(utcIso(first), "2024-11-03T05:30:00.000Z");

  const second = toZone(fromUtcInstant("2024-11-03T06:30:00.000Z"), "America/New_York");
  assert.equal(formatWithZoneAbbrev(second, "America/New_York"), "2024-11-03 01:30 EST");
  assert.notEqual(utcIso(first), utcIso(second));
});

test("computes business hour overlap between zones", () => {
  const ny = businessInterval("2024-07-01", "America/New_York", 9, 17);
  const london = businessInterval("2024-07-01", "Europe/London", 9, 17);
  const tokyo = businessInterval("2024-07-01", "Asia/Tokyo", 9, 17);

  assert.equal(overlapHours(ny, london), 3);
  assert.equal(overlapHours(ny, tokyo), 0);
});

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.