A free time zone and sun API
Current time in any IANA zone, every zone's offset right now, sunrise and sunset for any coordinate, moon phase, a DST-correct wall clock converter, and a catalogue of 6,338 cities and 243 countries. No key, no signup, no quota form to fill in. Call it from a browser, a script or a Raspberry Pi.
The base URL is https://dayssincedate.com/api/v1. Every endpoint is a GET, every response is JSON, and every response allows any origin, so you can call this straight from client-side JavaScript without a proxy. There is nothing to install and nothing to register.
Try it now
curl -s "https://dayssincedate.com/api/v1/time/Asia/Tokyo"
const r = await fetch('https://dayssincedate.com/api/v1/convert?from=Europe/London&to=Asia/Kolkata&time=2026-07-04T09:00');
const j = await r.json();
console.log(j.to.iso, j.to.abbreviation, j.differenceText);
What it is built on
Every offset, abbreviation and daylight saving transition is read from the IANA time zone database that ships inside Node, through Intl, at the instant of your request. Nothing here carries a hand-written offset table, because a hand-written table is wrong twice a year in every zone that moves its clocks and permanently wrong in any zone that changes its rules. Sun times use the NOAA solar position algorithm and moon times use the Meeus lunar theory, both of which the site's own 90,645 pages are built on: the API and the page for the same city are computed by the same functions and cannot disagree.
Half-hour and 45-minute zones are handled properly. Kathmandu is UTC+05:45, Adelaide is UTC+09:30 or UTC+10:30 depending on the month, and Chatham Islands is UTC+12:45 or UTC+13:45. Polar day and polar night return nulls with a polar flag rather than a fabricated sunrise. Wall clock readings that never happened, or happened twice, are labelled as such instead of being quietly resolved.
Endpoints
Current time in a zone
GET /api/v1/time/{zone}
The clock in one IANA zone right now: the local ISO string with its offset, the epoch, the abbreviation actually in force, whether daylight saving is on, and the next time the zone changes its offset.
| Parameter | Meaning |
|---|---|
| {zone} | An IANA identifier (America/New_York), the slug form (america-new-york), or an abbreviation this site publishes pages for (est, pst, ist). An abbreviation names the zone, not the winter offset: est answers as Eastern Time and returns EDT in July. |
Live response from /api/v1/time/Asia/Kathmandu, status 200:
{
"zone": "Asia/Kathmandu",
"abbreviation": "NPT",
"datetime": "2026-09-25T19:12:49.059+05:45",
"utcDatetime": "2026-09-25T13:27:49.059Z",
"epochMs": 1790342869059,
"unixtime": 1790342869,
"utcOffset": "+05:45",
"utcOffsetMinutes": 345,
"utcOffsetLabel": "UTC+5:45",
"date": "2026-09-25",
"time": "19:12:49",
"dayOfWeek": 5,
"dayOfWeekName": "Friday",
"dayOfYear": 268,
"weekNumber": 39,
"dst": {
"observedThisYear": false,
"active": false,
"standardOffsetMinutes": 345,
"savingMinutes": 0
},
"nextTransition": null,
"meta": {
"generatedAt": "2026-09-25T13:27:49.060Z",
"docs": "https://dayssincedate.com/api",
"source": {
"name": "IANA Time Zone Database",
"url": "https://www.iana.org/time-zones",
"licence": "Public domain",
... 4 more lines
Every zone and its current offset
GET /api/v1/zones
All 419 published IANA zones with the offset each is on at this moment, in one response, so a client can populate a picker with a single call. Filter by offset to find everyone currently reading the same clock.
| Parameter | Meaning |
|---|---|
| offset | Optional. +05:45, -4 or -240. Colons mean hours and minutes; a bare number of 14 or less means hours, anything larger means minutes. |
| limit | Optional, default and maximum 500. |
| skip | Optional. Rows to skip, for paging. |
Live response from /api/v1/zones?offset=%2B05%3A45, status 200:
{
"total": 1,
"count": 1,
"limit": 500,
"skip": 0,
"filter": {
"utcOffsetMinutes": 345,
"utcOffset": "+05:45"
},
"zones": [
{
"zone": "Asia/Kathmandu",
"utcOffset": "+05:45",
"utcOffsetMinutes": 345,
"abbreviation": "NPT"
}
],
"meta": {
"generatedAt": "2026-09-25T13:27:49.065Z",
"docs": "https://dayssincedate.com/api",
"source": {
"name": "IANA Time Zone Database",
"url": "https://www.iana.org/time-zones",
"licence": "Public domain",
"credit": "Time zone rules from the IANA database, read through Intl at the instant of the request."
}
}
}
One city
GET /api/v1/city/{slug}
A city from the 6,338 row catalogue: coordinates, country, zone, the clock there now, and the full solar day, twilight bands and golden hour included.
| Parameter | Meaning |
|---|---|
| {slug} | A catalogue slug, for example london, new-york, munich-germany. Find one with the cities endpoint below. |
Live response from /api/v1/city/reykjavik, status 200:
{
"city": {
"slug": "reykjavik",
"name": "Reykjavik",
"label": "Reykjavik, Iceland",
"region": "Capital Region",
"country": "Iceland",
"countryCode": "IS",
"latitude": 64.1466,
"longitude": -21.9426,
"population": 118918,
"timeZone": "Atlantic/Reykjavik",
"hemisphere": "northern"
},
"time": {
"zone": "Atlantic/Reykjavik",
"abbreviation": "GMT",
"datetime": "2026-09-25T13:27:49.065+00:00",
"utcDatetime": "2026-09-25T13:27:49.065Z",
"epochMs": 1790342869065,
"unixtime": 1790342869,
"utcOffset": "+00:00",
"utcOffsetMinutes": 0,
"utcOffsetLabel": "UTC+0",
"date": "2026-09-25",
"time": "13:27:49",
"dayOfWeek": 5,
"dayOfWeekName": "Friday",
"dayOfYear": 268,
"weekNumber": 39,
... 138 more lines
Search the city catalogue
GET /api/v1/cities
Search and filter 6,338 cities. Results are ranked by exact name first, then name prefix, then anywhere in the label, with population breaking ties inside each band. So "york" returns York before New York, and "new" returns New York first.
| Parameter | Meaning |
|---|---|
| q | Optional. A name fragment, 60 characters or fewer. Accents and punctuation are ignored. |
| country | Optional. A country name, its slug, or its ISO 3166-1 alpha-2 code. |
| limit | Optional, default 25, maximum 100. |
| skip | Optional. Rows to skip, for paging. |
Live response from /api/v1/cities?q=york&limit=3, status 200:
{
"query": {
"q": "york",
"country": null
},
"total": 3,
"count": 3,
"limit": 3,
"skip": 0,
"cities": [
{
"slug": "york",
"name": "York",
"label": "York, United Kingdom",
"region": "England",
"country": "United Kingdom",
"countryCode": "GB",
"latitude": 53.9576,
"longitude": -1.0827,
"population": 156135,
"timeZone": "Europe/London",
"hemisphere": "northern"
},
{
"slug": "new-york",
"name": "New York",
"label": "New York, NY",
"region": "NY",
"country": "United States",
"countryCode": "US",
... 34 more lines
Convert a wall clock between zones
GET /api/v1/convert
Take a clock reading written in one zone and read it in another, with both offsets resolved at that instant rather than today. The example is 1:30am on the morning the United States falls back, a reading that happens twice, which is why the response says so.
| Parameter | Meaning |
|---|---|
| from | Required. The zone the reading is written in. |
| to | Required. The zone to read it in. |
| time | Optional, defaults to now in from. A bare wall clock, YYYY-MM-DDTHH:MM. A space may replace the T and seconds are accepted and ignored. An offset or a Z is rejected: a string carrying its own offset is already an instant and does not need converting. |
Live response from /api/v1/convert?from=America/New_York&to=Australia/Adelaide&time=2026-11-01T01%3A30, status 200:
{
"from": {
"zone": "America/New_York",
"requested": "2026-11-01T01:30",
"iso": "2026-11-01T01:30:00-04:00",
"utcOffset": "-04:00",
"utcOffsetMinutes": -240,
"abbreviation": "EDT"
},
"to": {
"zone": "Australia/Adelaide",
"iso": "2026-11-01T16:00:00+10:30",
"utcOffset": "+10:30",
"utcOffsetMinutes": 630,
"abbreviation": "ACDT"
},
"utc": "2026-11-01T05:30:00.000Z",
"epochMs": 1793511000000,
"differenceMinutes": 870,
"differenceText": "14 hours 30 minutes",
"dayShift": 0,
"wallClock": "ambiguous",
"usedNow": false,
"meta": {
"generatedAt": "2026-09-25T13:27:49.080Z",
"docs": "https://dayssincedate.com/api",
"source": {
"name": "IANA Time Zone Database",
"url": "https://www.iana.org/time-zones",
"licence": "Public domain",
... 4 more lines
Sun times for a coordinate
GET /api/v1/sun
Sunrise, sunset, solar noon, day length, the three twilight bands, golden hour and blue hour. Nulls are real answers: above the Arctic circle in June there is no sunrise, and the response says polar day rather than inventing one.
| Parameter | Meaning |
|---|---|
| lat | Required. Degrees, north positive, -90 to 90. |
| lon | Required. Degrees, east positive, -180 to 180. |
| tz | Optional, defaults to Etc/UTC. The zone the returned clock readings are in. There is no coordinate to zone lookup here: use the city endpoint if you want one done for you. |
| date | Optional, defaults to today in tz. YYYY-MM-DD, between 1900 and 2100. |
Live response from /api/v1/sun?lat=78.22&lon=15.63&tz=Arctic/Longyearbyen&date=2026-06-21, status 200:
{
"location": {
"latitude": 78.22,
"longitude": 15.63,
"timeZone": "Arctic/Longyearbyen"
},
"sun": {
"date": "2026-06-21",
"sunrise": null,
"sunset": null,
"solarNoon": {
"iso": "2026-06-21T12:59:17+02:00",
"epochMs": 1782039557707
},
"dayLength": {
"ms": 86400000,
"seconds": 86400,
"text": "24 hours"
},
"polar": "day",
"twilight": {
"civil": {
"dawn": null,
"dusk": null
},
"nautical": {
"dawn": null,
"dusk": null
},
"astronomical": {
... 41 more lines
Moon times and phase
GET /api/v1/moon
Moonrise, moonset, the phase name, the lit fraction and the moon age, plus its altitude and azimuth. Moonrise and moonset can each be null on a real day, because the moon rises about fifty minutes later each day and some days it does not manage it before midnight.
| Parameter | Meaning |
|---|---|
| lat | Required. Degrees, north positive. |
| lon | Required. Degrees, east positive. |
| tz | Optional, defaults to Etc/UTC. |
| date | Optional, defaults to today in tz. |
Live response from /api/v1/moon?lat=-33.87&lon=151.21&tz=Australia/Sydney, status 200:
{
"location": {
"latitude": -33.87,
"longitude": 151.21,
"timeZone": "Australia/Sydney"
},
"date": "2026-09-25",
"moonrise": {
"iso": "2026-09-25T16:27:20+10:00",
"epochMs": 1790317640488
},
"moonset": {
"iso": "2026-09-25T04:39:13+10:00",
"epochMs": 1790275153923
},
"additionalRises": [],
"additionalSets": [],
"alwaysUp": false,
"alwaysDown": false,
"phase": {
"name": "waxing gibbous",
"illuminationPercent": 97.02,
"fraction": 0.97017,
"ageDays": 13.94,
"waxing": true,
"phaseAngle": 19.891,
"distanceKm": 386340.5
},
"position": {
"altitude": -45.702,
... 17 more lines
Every country
GET /api/v1/countries
Every country and territory with its capital, its full zone list and the time in its main zone right now. Useful for anything that needs to turn a country into a clock.
| Parameter | Meaning |
|---|---|
| continent | Optional. Africa, Asia, Europe, North America, South America, Oceania or Antarctica. |
| limit | Optional, default and maximum 300. |
| skip | Optional. Rows to skip, for paging. |
Live response from /api/v1/countries?continent=Oceania&limit=3, status 200:
{
"total": 27,
"count": 3,
"limit": 3,
"skip": 0,
"filter": {
"continent": "Oceania"
},
"countries": [
{
"name": "American Samoa",
"slug": "american-samoa",
"iso2": "AS",
"continent": "Oceania",
"capital": "Pago Pago",
"population": 44000,
"timeZone": "Pacific/Pago_Pago",
"timeZones": [
"Pacific/Pago_Pago"
],
"zoneCount": 1,
"currentTime": {
"iso": "2026-09-25T02:27:49-11:00",
"date": "2026-09-25",
"time": "02:27",
"utcOffset": "-11:00",
"utcOffsetMinutes": -660,
"abbreviation": "UTC-11"
}
},
... 65 more lines
Errors
Every failure has the same shape, carries a machine-readable code, a human message, and the correct HTTP status. An error is never returned inside a 200, and a stack trace is never returned at all.
{
"error": {
"code": "unknown_zone",
"status": 404,
"message": "\"Mars/Olympus_Mons\" is not a time zone this API knows.",
"parameter": "zone",
"got": "Mars/Olympus_Mons"
},
"meta": {
"docs": "https://dayssincedate.com/api"
}
}
| Code | Status | When |
|---|---|---|
| invalid_parameter | 400 | A parameter was present but unusable: a latitude of 200, a malformed date, a non-numeric limit. |
| missing_parameter | 400 | A required parameter was absent, for example from on the convert endpoint. |
| unknown_zone | 404 | The zone is not an identifier, slug or abbreviation this API knows. |
| unknown_city | 404 | No city in the catalogue has that slug. |
| not_found | 404 | The path names no endpoint. The response lists the ones that exist. |
| method_not_allowed | 405 | Anything other than GET, HEAD or OPTIONS. This API is read only. |
| rate_limited | 429 | Over the limit below. The response carries Retry-After. |
| internal_error | 500 | Something broke here. The detail is in our logs, not in your response. |
Rate limit
60 requests per minute per IP address, as a fixed window. Every response tells you where you stand:
X-RateLimit-Limit: 60, the ceiling for the window.X-RateLimit-Remaining: how many you have left in this window.X-RateLimit-Reset: the Unix second the window resets at.
Go over and you get a 429 with a Retry-After header in seconds. Preflight OPTIONS requests are answered but not counted, so a browser client does not spend half its quota on the browser's own behalf.
If 60 a minute is not enough, the answer is almost always caching rather than asking for more. Every response carries a Cache-Control header: five seconds for a clock reading, until the next UTC midnight for anything keyed on today, and a full day for a sun or moon request with an explicit date, because that answer is a property of the date and will never change. Honour those and a busy client makes a handful of calls an hour.
Licence and attribution
This is the part that is a condition, not a courtesy. If you publish anything built on these responses, you have to pass the credit on.
- City data: coordinates, population, region and time zone for all 6,338 cities come from GeoNames (
cities15000), licensed CC BY 4.0. Any response carrying a city row also carriesmeta.attributionnaming it. If you display that data, display the credit. - Weather data: the site's own pages use forecasts from MET Norway, licensed CC BY 4.0. No endpoint on this API serves weather, so nothing you fetch here carries that obligation, but the credit is stated here because the data is on the site you are reading.
- Time zone rules: the IANA time zone database, which is in the public domain.
- Everything else: the computed output is free to use, commercially included. A link back is welcome and is the only thing keeping this free, but it is not required.
There is no SLA
Being honest about this is more useful to you than a promise would be. This API runs on one small server alongside the rest of the site. There is no uptime guarantee, no support contract, no status page and no paid tier to escalate to. It has been stable and it is intended to stay that way, and the /v1 in the path is a real commitment that these response shapes will not change underneath you: new fields may be added, existing ones will not be removed or repurposed inside v1. But if your product would be broken by this endpoint being unreachable for an afternoon, cache the responses or run your own copy of the maths. Do not build a paging system on it.
If something is wrong, or you need an endpoint that is not here, the site has contact details on its about page.