chrono-node natural language dates with a fixed reference and timezone: working versions (tested 2026-10-15)
Parse phrases like "tomorrow at 9am", weekday names, ranges and dates inside sentences with chrono-node against a fixed reference instant and UTC offset, plus en.GB day-first parsing.
passed7 passed · 0 failed2026-10-15 20:08 UTC- Status
- passed
- Last passed
- 2026-10-15 20:08 UTC
- Tests
- 7 / 7
- Language
- TypeScript
- Runtime
- node v22.23.3
pinned versions3
chrono-node@2.10.3@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 38799498972
The code
Exactly the files that passed. Your agent can pull them with get_recipe("chrono-node-reference-date") (install), or see them on GitHub.
package.json
{
"name": "chrono-node-reference-date",
"private": true,
"type": "module",
"scripts": {
"test": "node --import tsx --test test/*.test.ts"
},
"dependencies": {
"chrono-node": "2.10.3"
},
"devDependencies": {
"@types/node": "26.6.5",
"tsx": "4.23.15"
}
}
src/parse.ts
import * as chrono from "chrono-node";
/**
* Parse natural-language dates against a fixed reference instant and timezone offset
* (minutes from UTC), so results never depend on the machine clock or TZ.
*/
export function parseWhen(text: string, ref: Date, tzOffsetMinutes: number, forwardDate = true) {
const results = chrono.parse(text, { instant: ref, timezone: tzOffsetMinutes }, { forwardDate });
return results.map((r) => ({
text: r.text,
index: r.index,
start: r.start.date().toISOString(),
end: r.end?.date().toISOString() ?? null,
certainHour: r.start.isCertain("hour"),
}));
}
export const parseOne = (text: string, ref: Date, tz: number) => chrono.parseDate(text, { instant: ref, timezone: tz }, { forwardDate: true })?.toISOString() ?? null;
/** British-style day/month input via the en.GB locale parser. */
export const parseGB = (text: string, ref: Date) => chrono.en.GB.parseDate(text, { instant: ref, timezone: 0 })?.toISOString() ?? null;
test/parse.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { parseWhen, parseOne, parseGB } from "../src/parse.ts";
// Thursday 2026-10-15 12:00 in Alaska (UTC-8) = 20:00Z
const ref = new Date("2026-10-15T20:00:00Z");
const AK = -480;
test("relative day and time in a fixed offset", () => {
assert.equal(parseOne("tomorrow at 9am", ref, AK), "2026-10-16T17:00:00.000Z");
assert.equal(parseOne("in 3 days", ref, AK), "2026-10-18T20:00:00.000Z");
});
test("weekday name with forwardDate picks the next one", () => {
assert.equal(parseOne("monday 8:30", ref, AK), "2026-10-19T16:30:00.000Z");
});
test("ranges give start and end", () => {
const [r] = parseWhen("Oct 20 2pm - 4pm", ref, AK);
assert.equal(r.start, "2026-10-20T22:00:00.000Z");
assert.equal(r.end, "2026-10-21T00:00:00.000Z");
});
test("finds dates inside a sentence with position and certainty", () => {
const rs = parseWhen("Class moved to Nov 1st, signup closes Friday", ref, AK);
assert.equal(rs.length, 2);
assert.equal(rs[0].text, "Nov 1st");
assert.equal(rs[0].index, 15);
assert.equal(rs[0].certainHour, false);
assert.equal(rs[1].text, "Friday");
});
test("UTC offset changes the instant", () => {
assert.equal(parseOne("2026-11-01 10:00", ref, 0), "2026-11-01T10:00:00.000Z");
assert.equal(parseOne("2026-11-01 10:00", ref, AK), "2026-11-01T18:00:00.000Z");
});
test("en.GB reads day before month", () => {
assert.equal(parseGB("03/04/2027 noon", ref), "2027-04-03T12:00:00.000Z");
});
test("no date returns empty", () => {
assert.deepEqual(parseWhen("bring your hard hat", ref, AK), []);
assert.equal(parseOne("nothing here", ref, AK), null);
});
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.