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
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.