Free JSON time API
Keyless, CORS-open, no signup, no tracking. Every response is computed from the clock plus the IANA tz database — there is no upstream cost to pass on, so there is nothing to meter. Published limit: 10 requests per second per IP, burstable; go over it politely and we will talk rather than block.
GET /api/now current UTC
request
curl https://utctime.app/api/now
response
{
"utc_iso": "2026-08-12T23:19:00Z",
"utc_rfc3339": "2026-08-12T23:19:00+00:00",
"unix": 1786576740,
"unix_ms": 1786576740260,
"day_of_week": 3,
"day_of_year": 224,
"week_number": 33
}
day_of_week is ISO numbering: 1 = Monday, 7 = Sunday.
GET /api/now/{iana-zone} any zone, with DST state
https://utctime.app/api/now/Asia/Kolkata
run it
{
"utc_iso": "…",
"unix": …,
"timezone": "Asia/Kolkata",
"datetime": "…+05:30",
"local_iso": "…+05:30",
"abbreviation": "IST",
"utc_offset": "+05:30",
"utc_offset_minutes": 330,
"dst": false,
"dst_next_transition": null,
"dst_next_abbreviation": null,
"dst_next_offset": null
}
dst_next_transition is the next UTC instant at which that zone's offset changes, or null for zones that do not shift. Nobody else publishes this, and it is what lets a device schedule its own re-sync.
GET /api/zones every IANA name we accept
https://utctime.app/api/zones
run it
{ "count": 597, "zones": ["Africa/Abidjan", "Africa/Accra", … ] }
GET /api/convert between any two zones
https://utctime.app/api/convert?from=UTC&to=America/New_York&t=1735689600
run it
{
"input": "1735689600",
"input_kind": "s",
"unix": 1735689600,
"utc_iso": "2025-01-01T00:00:00Z",
"from": { "timezone": "UTC", "abbreviation": "UTC", "datetime": "…", "utc_offset": "+00:00", "dst": false },
"to": { "timezone": "America/New_York", "abbreviation": "EST", "datetime": "…", "utc_offset": "-05:00", "dst": false },
"difference_minutes": -300
}
| Parameter | Default | Accepts |
|---|---|---|
| from | UTC | any IANA zone name |
| to | UTC | any IANA zone name |
| t | now | Unix seconds / ms / µs / ns (auto-detected), or an ISO 8601 string |
Call it from anywhere
JavaScript
const r = await fetch('https://utctime.app/api/now');
const { utc_iso, unix } = await r.json();
// CORS is open — no proxy, no key
Python
import requests
r = requests.get('https://utctime.app/api/now/Europe/London', timeout=5)
print(r.json()['datetime'], r.json()['abbreviation'])
Bash
curl -s https://utctime.app/api/now | jq -r .utc_iso
date -u -s "$(curl -s https://utctime.app/api/now | jq -r .utc_iso)" # sync a box
CircuitPython / ESP32
import adafruit_requests
r = requests.get("https://utctime.app/api/now/America/Chicago")
t = r.json()
# t["datetime"], t["unix"], t["dst_next_transition"]
Limits, honestly
| Auth | None. No key, no header, no Origin allowlist. |
| Rate limit | 10 requests/second/IP, burstable. A device polling once a minute is nowhere near it. |
| CORS | Access-Control-Allow-Origin: * on every response, errors included. |
| Caching | Cache-Control: public, max-age=1. /api/zones is cached for a day. |
| Errors | JSON with an error key and a real status code — never an HTML error page. |
| Stability | Fields get added, never removed or renamed. Ignore unknown keys. |
| Transport | HTTPS only — .app is HSTS-preloaded, so plain HTTP cannot work. |
API questions
Is the API really free and keyless?
Yes. No signup, no key, no Origin restriction. Every response is computable from the clock and tzdata, so there is no upstream cost to pass on. The published limit is 10 requests per second per IP with burst headroom; if you need more than that, get in touch rather than sharding across addresses.
Can I call it from a browser?
Yes — every endpoint sends Access-Control-Allow-Origin: *, so fetch() from any page works with no proxy.
How accurate is it?
The host is NTP-synchronised and responses carry a Date header plus a microsecond-precision timestamp in the body. Network latency, not the server, is your error bound: for sub-second accuracy measure the round trip and subtract half of it, which is what the skew badge on the homepage does.
What happened to worldtimeapi.org?
It has been unreliable for a long stretch and unreachable in our testing, which stranded a lot of ESP32, CircuitPython and Power BI projects that had hard-coded it. Our migration guide maps its endpoint shapes onto ours, and compatibility aliases accept its URL form directly so a one-line base-URL change is usually enough.
Will the response shape change?
Fields will be added, never removed or renamed, and additions go to the end of the object. Parse defensively anyway — ignore unknown keys rather than failing on them.