Days Since Date Search

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.

ParameterMeaning
{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.

ParameterMeaning
offsetOptional. +05:45, -4 or -240. Colons mean hours and minutes; a bare number of 14 or less means hours, anything larger means minutes.
limitOptional, default and maximum 500.
skipOptional. 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.

ParameterMeaning
{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.

ParameterMeaning
qOptional. A name fragment, 60 characters or fewer. Accents and punctuation are ignored.
countryOptional. A country name, its slug, or its ISO 3166-1 alpha-2 code.
limitOptional, default 25, maximum 100.
skipOptional. 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.

ParameterMeaning
fromRequired. The zone the reading is written in.
toRequired. The zone to read it in.
timeOptional, 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.

ParameterMeaning
latRequired. Degrees, north positive, -90 to 90.
lonRequired. Degrees, east positive, -180 to 180.
tzOptional, 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.
dateOptional, 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.

ParameterMeaning
latRequired. Degrees, north positive.
lonRequired. Degrees, east positive.
tzOptional, defaults to Etc/UTC.
dateOptional, 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.

ParameterMeaning
continentOptional. Africa, Asia, Europe, North America, South America, Oceania or Antarctica.
limitOptional, default and maximum 300.
skipOptional. 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"
  }
}
CodeStatusWhen
invalid_parameter400A parameter was present but unusable: a latitude of 200, a malformed date, a non-numeric limit.
missing_parameter400A required parameter was absent, for example from on the convert endpoint.
unknown_zone404The zone is not an identifier, slug or abbreviation this API knows.
unknown_city404No city in the catalogue has that slug.
not_found404The path names no endpoint. The response lists the ones that exist.
method_not_allowed405Anything other than GET, HEAD or OPTIONS. This API is read only.
rate_limited429Over the limit below. The response carries Retry-After.
internal_error500Something 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:

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.

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.