/api/time/convert
MCP tool time_convert Parses input and returns the instant in UTC, as Unix seconds and milliseconds, and in each zone of zones. The response says exactly how the input was read: the detected format, the inferred timestamp unit (with what the other units would have meant), and, for a wall-clock time without an offset, the zone used and whether that local time was unique, skipped by a DST gap, or repeated in a DST overlap.
Browser version (runs locally): Time & Time Zones.
Try it
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
input required | string (≤ 100 chars) | — | ISO 8601 / RFC 3339 (2026-10-13T14:30:00Z, 2026-10-13T14:30:00+02:00, 2026-10-13 14:30, 2026-10-13, 2026-W42-2, with an optional RFC 9557 [Zone/Name] suffix), RFC 2822, HTTP-date (IMF-fixdate, RFC 850, asctime), a Unix timestamp (seconds, milliseconds, microseconds or nanoseconds; decimals allowed), or now. |
unit | auto | seconds | milliseconds | microseconds | nanoseconds | auto | Unit of a numeric Unix timestamp. auto infers it from the magnitude: below 10^11 seconds, below 10^14 milliseconds, below 10^17 microseconds, otherwise nanoseconds. Only valid with numeric input. |
from_zone | string (≤ 64 chars) | — | Zone in which to read an input that has no UTC offset (2026-03-08T02:30). Required for such input; ignored when the input carries an offset or a Unix timestamp. |
disambiguation | compatible | earlier | later | reject | compatible | How to resolve a wall-clock time that falls in a DST gap or overlap (same meaning as in JavaScript Temporal). compatible: gap → shift forward by the gap length, overlap → earlier instant. earlier / later: pick that instant (in a gap, the instant before or after the gap). reject: fail with 422. |
zones | list of strings | UTC | Comma-separated (or JSON array) zones to show the instant in: IANA names, UTC, or fixed offsets such as +05:30. At most 20. |
formats | list of rfc2822 | http | sql | iso_basic | iso_week_date | iso_ordinal | human | — | Extra renderings added to each zone's formatted map: rfc2822 (Tue, 13 Oct 2026 14:30:00 +0200), http (HTTP-date, always GMT), sql (2026-10-13 14:30:00.000 +02:00), iso_basic (20261013T143000+0200), iso_week_date (2026-W42-2), iso_ordinal (2026-286), human (Tuesday, October 13, 2026 at 2:30:00 PM GMT+2). |
pattern | string (≤ 100 chars) | — | Custom format using Luxon tokens (e.g. yyyy-MM-dd HH:mm ZZZZ; quote literal text in single quotes). Added to formatted.pattern. English names. |
Also accepted on every endpoint: format (json | text).
Parameters may come from the query string, a JSON object body, an urlencoded or multipart form,
or (for input) a text/plain body.
Global parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
format | json | text | json | json returns the documented object. text returns only the primary value as text/plain (see "Text output"). |
Response 200 application/json
| Field | Type | Description |
|---|---|---|
input | object | |
input.input | string | The input as received (trimmed). |
input.format | "now" | "iso8601" | "rfc2822" | "http-date" | "unix" | How the input was parsed. |
input.unit | string | null | Unit of a Unix timestamp (seconds, milliseconds, microseconds, nanoseconds); null for other formats. |
input.unit_auto_detected | boolean | True when the timestamp unit was inferred from its magnitude. |
input.has_offset | boolean | False when the input was a wall-clock time without a UTC offset, resolved in local_zone. |
input.local_zone | string | null | Zone used to resolve a wall-clock input; null otherwise. |
input.local_time | string | null | For wall-clock input: unique, gap (did not exist; DST jump forward) or overlap (occurred twice; DST jump back). Null otherwise. |
input.notes | array of string | Every assumption made: auto-detected units and their alternatives, the zone used for wall-clock input, DST resolution, truncated precision. |
instant | object | |
instant.utc | string | The instant in UTC, ISO 8601 with Z. |
instant.unix_seconds | integer | Whole seconds since 1970-01-01T00:00:00Z, rounded down (floor). |
instant.unix_milliseconds | integer | Milliseconds since 1970-01-01T00:00:00Z. |
zones | array of object | One entry per requested zone, in request order. |
zones[].zone | string | Zone name as resolved: IANA name (letter case corrected), UTC, or UTC±HH:MM. |
zones[].iso | string | ISO 8601 / RFC 3339 with the UTC offset (Z for UTC). Milliseconds appear only when non-zero. |
zones[].local | string | Wall-clock date-time in the zone without an offset, YYYY-MM-DDTHH:mm:ss[.SSS]. |
zones[].date | string | Local calendar date, YYYY-MM-DD. |
zones[].time | string | Local time, HH:mm:ss (24-hour), with .SSS only when milliseconds are non-zero. |
zones[].offset | string | UTC offset, ±HH:MM. |
zones[].offset_minutes | integer | UTC offset in minutes (east positive), e.g. -240 for UTC-04:00. |
zones[].abbreviation | string | Short zone name as Intl (en-US) prints it: EDT, PST, or GMT+2 where English has no common abbreviation. |
zones[].offset_name | string | Long zone name, e.g. Eastern Daylight Time. |
zones[].dst | boolean | True when daylight saving time is in effect at this instant. |
zones[].weekday | string | English weekday name, e.g. Tuesday. |
zones[].weekday_number | integer | ISO 8601 weekday: 1 = Monday … 7 = Sunday. |
zones[].iso_week | string | ISO 8601 week, YYYY-Www (the week-numbering year can differ from the calendar year near 1 January). |
zones[].iso_week_year | integer | ISO 8601 week-numbering year. |
zones[].iso_week_number | integer | ISO 8601 week number, 1-53. |
zones[].day_of_year | integer | Ordinal day of the year, 1-366. |
zones[].formatted | map of string | Extra renderings requested with formats (keyed by format name) and pattern (key pattern). Empty when none were requested. |
warnings | array of string | Warnings about the zones given (fixed offsets, legacy or inverted names). |
Text output (format=text, text/plain): The ISO 8601 time in each requested zone, one per line.
Errors
Errors are JSON: {"error": "<message>", "code": "<code>", "param": "<name>"?}.
| Status | Code | When |
|---|---|---|
400 | invalid_parameter | A zone is unknown or an abbreviation, or unit is given for non-numeric input. |
422 | unprocessable_input | input is not a recognised format, is an impossible date (2026-02-30), is outside ±8.64e15 ms of 1970, has no offset and no from_zone, or falls in a DST gap/overlap with disambiguation=reject. |
400 | missing_parameter | A required parameter is absent. |
400 | unknown_parameter | A parameter name is not in the table above (typos are rejected, not ignored). |
413 | payload_too_large | The request body exceeds 1 MiB. |
405 | method_not_allowed | A method other than GET, POST or OPTIONS. |
Behaviour
- Idempotent: the same arguments always return the same result.
-
Requires a client ID and secret (authentication). Each call is
recorded as one metadata row against your client ID; inputs and outputs are never stored or
logged. Responses carry
cache-control: no-store. - CORS: any origin may call this endpoint from a browser, using your credentials.
Examples
Responses below were produced by running each request through this code at build time. Long strings are shortened.
Unix timestamp (unit auto-detected) to two zones
curl 'https://util.caruana.me/api/time/convert?input=1791900000&zones=UTC%2CEurope%2FParis'
Response 200
{
"input": {
"input": "1791900000",
"format": "unix",
"unit": "seconds",
"unit_auto_detected": true,
"has_offset": true,
"local_zone": null,
"local_time": null,
"notes": [
"Unit auto-detected as seconds because the magnitude is below 10^11. For comparison, as milliseconds it would be 1970-01-… (90 more characters)"
]
},
"instant": {
"utc": "2026-10-13T14:00:00Z",
"unix_seconds": 1791900000,
"unix_milliseconds": 1791900000000
},
"zones": [
{
"zone": "UTC",
"iso": "2026-10-13T14:00:00Z",
"local": "2026-10-13T14:00:00",
"date": "2026-10-13",
"time": "14:00:00",
"offset": "+00:00",
"offset_minutes": 0,
"abbreviation": "UTC",
"offset_name": "UTC",
"dst": false,
"weekday": "Tuesday",
"weekday_number": 2,
"iso_week": "2026-W42",
"iso_week_year": 2026,
"iso_week_number": 42,
"day_of_year": 286,
"formatted": {}
},
{
"zone": "Europe/Paris",
"iso": "2026-10-13T16:00:00+02:00",
"local": "2026-10-13T16:00:00",
"date": "2026-10-13",
"time": "16:00:00",
"offset": "+02:00",
"offset_minutes": 120,
"abbreviation": "GMT+2",
"offset_name": "Central European Summer Time",
"dst": true,
"weekday": "Tuesday",
"weekday_number": 2,
"iso_week": "2026-W42",
"iso_week_year": 2026,
"iso_week_number": 42,
"day_of_year": 286,
"formatted": {}
}
],
"warnings": []
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "time_convert",
"arguments": {
"input": "1791900000",
"zones": [
"UTC",
"Europe/Paris"
]
}
}
}Wall-clock time inside a DST gap
curl 'https://util.caruana.me/api/time/convert?input=2026-03-08T02%3A30&from_zone=America%2FNew_York&zones=UTC'
Response 200
{
"input": {
"input": "2026-03-08T02:30",
"format": "iso8601",
"unit": null,
"unit_auto_detected": false,
"has_offset": false,
"local_zone": "America/New_York",
"local_time": "gap",
"notes": [
"No offset in the input: read as wall-clock time in America/New_York (set by from_zone).",
"2026-03-08T02:30:00 does not exist in America/New_York: it falls in a 60-minute DST gap. Resolved to 2026-03-08T03:30:00… (79 more characters)"
]
},
"instant": {
"utc": "2026-03-08T07:30:00Z",
"unix_seconds": 1772955000,
"unix_milliseconds": 1772955000000
},
"zones": [
{
"zone": "UTC",
"iso": "2026-03-08T07:30:00Z",
"local": "2026-03-08T07:30:00",
"date": "2026-03-08",
"time": "07:30:00",
"offset": "+00:00",
"offset_minutes": 0,
"abbreviation": "UTC",
"offset_name": "UTC",
"dst": false,
"weekday": "Sunday",
"weekday_number": 7,
"iso_week": "2026-W10",
"iso_week_year": 2026,
"iso_week_number": 10,
"day_of_year": 67,
"formatted": {}
}
],
"warnings": []
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "time_convert",
"arguments": {
"input": "2026-03-08T02:30",
"from_zone": "America/New_York",
"zones": [
"UTC"
]
}
}
}RFC 2822 to Tokyo, with extra formats
curl 'https://util.caruana.me/api/time/convert?input=Tue%2C%2013%20Oct%202026%2014%3A30%3A00%20%2B0200&zones=Asia%2FTokyo&formats=http%2Ciso_week_date%2Chuman'
Response 200
{
"input": {
"input": "Tue, 13 Oct 2026 14:30:00 +0200",
"unit": null,
"unit_auto_detected": false,
"has_offset": true,
"local_zone": null,
"local_time": null,
"notes": [],
"format": "rfc2822"
},
"instant": {
"utc": "2026-10-13T12:30:00Z",
"unix_seconds": 1791894600,
"unix_milliseconds": 1791894600000
},
"zones": [
{
"zone": "Asia/Tokyo",
"iso": "2026-10-13T21:30:00+09:00",
"local": "2026-10-13T21:30:00",
"date": "2026-10-13",
"time": "21:30:00",
"offset": "+09:00",
"offset_minutes": 540,
"abbreviation": "GMT+9",
"offset_name": "Japan Standard Time",
"dst": false,
"weekday": "Tuesday",
"weekday_number": 2,
"iso_week": "2026-W42",
"iso_week_year": 2026,
"iso_week_number": 42,
"day_of_year": 286,
"formatted": {
"http": "Tue, 13 Oct 2026 12:30:00 GMT",
"iso_week_date": "2026-W42-2",
"human": "Tuesday, October 13, 2026 at 9:30:00 PM GMT+9"
}
}
],
"warnings": []
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "time_convert",
"arguments": {
"input": "Tue, 13 Oct 2026 14:30:00 +0200",
"zones": [
"Asia/Tokyo"
],
"formats": [
"http",
"iso_week_date",
"human"
]
}
}
}