at date Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now.
Moon phase, illumination, moonrise, moonset, lunar transit and topocentric position for any coordinate, plus every primary phase instant of a year. No key.
Authoritative reference data or standards computation
at is an absolute instant (a bare date means UTC midnight); omit it for now. Every value is geocentric — a topocentric observer's illuminated fraction differs by up to about 0.7 percentage points near the horizon, and that difference is not modelled.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
at | date | example: 2026-07-29T14:36:00Z | Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now. |
tz | string | default: UTC example: Europe/Copenhagen | IANA zone used to render `localTime` and every `local` inside the phase objects, case-insensitive. It never moves the instant; unknown ids return a 400. |
at date Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now.
tz string IANA zone used to render `localTime` and every `local` inside the phase objects, case-insensitive. It never moves the instant; unknown ids return a 400.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
fields | list | example: at,timezone | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: nextFullMoon | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
at | string (ISO 8601 UTC) | The evaluated instant in UTC. | 2026-07-29T14:36:00.000Z |
timezone | string | Canonical IANA id used to render `localTime` and every `local` inside the phase objects. It never moves the instant. | Europe/Copenhagen |
localTime | string (YYYY-MM-DDTHH:mm:ss) | Naive local wall clock of `at` in `timezone`. | 2026-07-29T16:36:00 |
illuminatedFraction | float (0 to 1) | Fraction of the Moon's apparent disk that is sunlit, 0 at new and 1 at full. Geocentric — a topocentric observer's value differs by up to about 0.7 percentage points near the horizon. It never quite reaches 0 or 1: rounded to the five decimals returned here, the primary instants of 2026-2030 span 0.99811 to 1 at full and 0 to 0.00192 at new. | 0.99967 |
phaseAngleDegrees | float (0 to 180) | Sun–Moon–Earth phase angle, derived from the true geocentric Sun–Earth–Moon separation, which includes the Moon's ecliptic latitude. It reaches exactly 0° at full and 180° at new **only when the Moon is at a node — that is, at an eclipse**: measured over every primary instant of 2026-2030 the full moons span 0.01°-4.99° and the new moons 174.98°-179.86°, so neither endpoint is ever actually attained. | 2.073 |
elongationDegrees | float (0 to 360) | Geocentric elongation of the Moon east of the Sun in apparent ecliptic longitude: 0° new, 90° first quarter, 180° full, 270° last quarter. This is the quantity `phaseName`, `waxing` and the primary-phase root solve are all derived from. | 180.0031 |
phaseName | string | Conventional name for `elongationDegrees`: `new`, `waxing-crescent`, `first-quarter`, `waxing-gibbous`, `full`, `waning-gibbous`, `last-quarter` or `waning-crescent`. **The sector boundaries are this API's documented convention, not a standard** — eight 45°-wide sectors centred on the four primary instants (`new` is 337.5°–360° and 0°–22.5°, `waxing-crescent` 22.5°–67.5°, and so on). Other publishers bin differently, so near a boundary a name can disagree with theirs; `nextPrimaryPhase` and /api/moon/phases carry the exact instants. | full |
waxing | boolean | True while `elongationDegrees` is in [0, 180) — the illuminated fraction is growing. Exactly 180.0 is reported as false (waning). | false |
ageDays | float | Days elapsed since `previousNewMoon.instant`. Ranges 0 to about 29.83, and is exactly 0 at a published new-moon instant. | 15.20313 |
lunationNumber | integer | Brown Lunation Number of the cycle `at` falls in — lunation 1 is the cycle that began at the new moon of 1923 January 17 (02:41 UT). Always equal to the lunation of `previousNewMoon`. | 1281 |
distanceKm | float | Geometric geocentric centre-to-centre distance in km. Sampled hourly over 2026-2036 it ranges 356 445.9 to 406 670.5. | 399616.1 |
apparentDiameterDegrees | float | Geocentric apparent angular diameter of the lunar disk, from the IAU mean lunar radius applied to the horizontal parallax. Measured over 2026-2036 it ranges 0.4896° to 0.5585°. | 0.4982 |
previousNewMoon | object | The new-moon instant that starts this lunation. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable. | {"instant":"2026-07-14T09:43:30.000Z","local":"2026-07-14T11:43:30","deltaTSeconds":75.4} |
nextPrimaryPhase | object | The next of the four primary phases strictly after `at`, with `phase` naming which one (`new`, `first-quarter`, `full` or `last-quarter`). Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable. | {"phase":"last-quarter","instant":"2026-08-06T02:21:22.000Z","local":"2026-08-06T04:21:22","deltaTSeconds":75.5} |
nextFullMoon | object | The next full-moon instant strictly after `at`; at a published full-moon instant this is the following month's. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable. | {"instant":"2026-08-28T04:18:25.000Z","local":"2026-08-28T06:18:25","deltaTSeconds":75.5} |
at string (ISO 8601 UTC) The evaluated instant in UTC.
example: 2026-07-29T14:36:00.000Z
timezone string Canonical IANA id used to render `localTime` and every `local` inside the phase objects. It never moves the instant.
example: Europe/Copenhagen
localTime string (YYYY-MM-DDTHH:mm:ss) Naive local wall clock of `at` in `timezone`.
example: 2026-07-29T16:36:00
illuminatedFraction float (0 to 1) Fraction of the Moon's apparent disk that is sunlit, 0 at new and 1 at full. Geocentric — a topocentric observer's value differs by up to about 0.7 percentage points near the horizon. It never quite reaches 0 or 1: rounded to the five decimals returned here, the primary instants of 2026-2030 span 0.99811 to 1 at full and 0 to 0.00192 at new.
example: 0.99967
phaseAngleDegrees float (0 to 180) Sun–Moon–Earth phase angle, derived from the true geocentric Sun–Earth–Moon separation, which includes the Moon's ecliptic latitude. It reaches exactly 0° at full and 180° at new **only when the Moon is at a node — that is, at an eclipse**: measured over every primary instant of 2026-2030 the full moons span 0.01°-4.99° and the new moons 174.98°-179.86°, so neither endpoint is ever actually attained.
example: 2.073
elongationDegrees float (0 to 360) Geocentric elongation of the Moon east of the Sun in apparent ecliptic longitude: 0° new, 90° first quarter, 180° full, 270° last quarter. This is the quantity `phaseName`, `waxing` and the primary-phase root solve are all derived from.
example: 180.0031
phaseName string Conventional name for `elongationDegrees`: `new`, `waxing-crescent`, `first-quarter`, `waxing-gibbous`, `full`, `waning-gibbous`, `last-quarter` or `waning-crescent`. **The sector boundaries are this API's documented convention, not a standard** — eight 45°-wide sectors centred on the four primary instants (`new` is 337.5°–360° and 0°–22.5°, `waxing-crescent` 22.5°–67.5°, and so on). Other publishers bin differently, so near a boundary a name can disagree with theirs; `nextPrimaryPhase` and /api/moon/phases carry the exact instants.
example: full
waxing boolean True while `elongationDegrees` is in [0, 180) — the illuminated fraction is growing. Exactly 180.0 is reported as false (waning).
example: false
ageDays float Days elapsed since `previousNewMoon.instant`. Ranges 0 to about 29.83, and is exactly 0 at a published new-moon instant.
example: 15.20313
lunationNumber integer Brown Lunation Number of the cycle `at` falls in — lunation 1 is the cycle that began at the new moon of 1923 January 17 (02:41 UT). Always equal to the lunation of `previousNewMoon`.
example: 1281
distanceKm float Geometric geocentric centre-to-centre distance in km. Sampled hourly over 2026-2036 it ranges 356 445.9 to 406 670.5.
example: 399616.1
apparentDiameterDegrees float Geocentric apparent angular diameter of the lunar disk, from the IAU mean lunar radius applied to the horizontal parallax. Measured over 2026-2036 it ranges 0.4896° to 0.5585°.
example: 0.4982
previousNewMoon object The new-moon instant that starts this lunation. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.
example: {"instant":"2026-07-14T09:43:30.000Z","local":"2026-07-14T11:43:30","deltaTSeconds":75.4}
nextPrimaryPhase object The next of the four primary phases strictly after `at`, with `phase` naming which one (`new`, `first-quarter`, `full` or `last-quarter`). Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.
example: {"phase":"last-quarter","instant":"2026-08-06T02:21:22.000Z","local":"2026-08-06T04:21:22","deltaTSeconds":75.5}
nextFullMoon object The next full-moon instant strictly after `at`; at a published full-moon instant this is the following month's. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`) and `deltaTSeconds`, the TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.
example: {"instant":"2026-08-28T04:18:25.000Z","local":"2026-08-28T06:18:25","deltaTSeconds":75.5}
/api/moon/phase?tz=Europe/Copenhagen {
"data": {
"at": "2026-07-30T15:14:08.000Z",
"timezone": "Europe/Copenhagen",
"localTime": "2026-07-30T17:14:08",
"illuminatedFraction": 0.98972,
"phaseAngleDegrees": 11.6412,
"elongationDegrees": 191.631,
"phaseName": "full",
"waxing": false,
"ageDays": 16.22961,
"lunationNumber": 1281,
"distanceKm": 396703.3,
"apparentDiameterDegrees": 0.5019,
"previousNewMoon": {
"instant": "2026-07-14T09:43:30.000Z",
"local": "2026-07-14T11:43:30",
"deltaTSeconds": 75.4
},
"nextPrimaryPhase": {
"phase": "last-quarter",
"instant": "2026-08-06T02:21:22.000Z",
"local": "2026-08-06T04:21:22",
"deltaTSeconds": 75.5
},
"nextFullMoon": {
"instant": "2026-08-28T04:18:25.000Z",
"local": "2026-08-28T06:18:25",
"deltaTSeconds": 75.5
}
},
"meta": {
"endpoint": "moon",
"route": "/phase",
"params": {
"tz": "Europe/Copenhagen",
"at": "2026-07-30T15:14:08.000Z"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/phase?at=2026-07-29T14:36:00Z {
"data": {
"at": "2026-07-29T14:36:00.000Z",
"timezone": "UTC",
"localTime": "2026-07-29T14:36:00",
"illuminatedFraction": 0.99967,
"phaseAngleDegrees": 2.073,
"elongationDegrees": 180.0031,
"phaseName": "full",
"waxing": false,
"ageDays": 15.20313,
"lunationNumber": 1281,
"distanceKm": 399616.1,
"apparentDiameterDegrees": 0.4982,
"previousNewMoon": {
"instant": "2026-07-14T09:43:30.000Z",
"local": "2026-07-14T09:43:30",
"deltaTSeconds": 75.4
},
"nextPrimaryPhase": {
"phase": "last-quarter",
"instant": "2026-08-06T02:21:22.000Z",
"local": "2026-08-06T02:21:22",
"deltaTSeconds": 75.5
},
"nextFullMoon": {
"instant": "2026-08-28T04:18:25.000Z",
"local": "2026-08-28T04:18:25",
"deltaTSeconds": 75.5
}
},
"meta": {
"endpoint": "moon",
"route": "/phase",
"params": {
"at": "2026-07-29T14:36:00.000Z",
"tz": "UTC"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/phase?at=1992-04-12T00:00:00Z {
"data": {
"at": "1992-04-12T00:00:00.000Z",
"timezone": "UTC",
"localTime": "1992-04-12T00:00:00",
"illuminatedFraction": 0.67864,
"phaseAngleDegrees": 69.0671,
"elongationDegrees": 110.8361,
"phaseName": "first-quarter",
"waxing": true,
"ageDays": 8.79066,
"lunationNumber": 857,
"distanceKm": 368404.9,
"apparentDiameterDegrees": 0.5404,
"previousNewMoon": {
"instant": "1992-04-03T05:01:27.000Z",
"local": "1992-04-03T05:01:27",
"deltaTSeconds": 58.6
},
"nextPrimaryPhase": {
"phase": "full",
"instant": "1992-04-17T04:42:28.000Z",
"local": "1992-04-17T04:42:28",
"deltaTSeconds": 58.6
},
"nextFullMoon": {
"instant": "1992-04-17T04:42:28.000Z",
"local": "1992-04-17T04:42:28",
"deltaTSeconds": 58.6
}
},
"meta": {
"endpoint": "moon",
"route": "/phase",
"params": {
"at": "1992-04-12",
"tz": "UTC"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} date is a local civil date in tz; omit it for today in that zone. The route reports the events that actually fall inside that local date — it does not pair a rise with a set. Because the lunar day is about 24 h 50 min long, a civil date can contain a moonset with no moonrise (or the reverse), and moonset can precede moonrise.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
lat
required
| float | allowed: -90 – 90 example: 55.6761 | Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90). |
lng
required
| float | allowed: -180 – 180 example: 12.5683 | Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180). |
date | date | example: 2026-07-29 | Local civil date (YYYY-MM-DD) in the resolved zone, years 1900–2100. Defaults to today in that zone. An RFC 3339 timestamp is accepted too and is reduced to the local civil date that instant falls on in `tz` — except at exactly 00:00 UTC, which is indistinguishable from the bare date and is read as that calendar date. |
tz | string | default: UTC example: Europe/Copenhagen | IANA zone used to resolve the local civil date, its start and end instants, and every `local` wall clock, case-insensitive. Unknown ids return a 400 — browse them at /api/timezones. |
lat float required Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90).
lng float required Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180).
date date Local civil date (YYYY-MM-DD) in the resolved zone, years 1900–2100. Defaults to today in that zone. An RFC 3339 timestamp is accepted too and is reduced to the local civil date that instant falls on in `tz` — except at exactly 00:00 UTC, which is indistinguishable from the bare date and is read as that calendar date.
tz string IANA zone used to resolve the local civil date, its start and end instants, and every `local` wall clock, case-insensitive. Unknown ids return a 400 — browse them at /api/timezones.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
fields | list | example: date,timezone | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: extraEvents | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
date | string (YYYY-MM-DD) | The local civil date the results describe, in the resolved zone. | 2026-07-29 |
timezone | string | Canonical IANA id used to resolve the local date, its start and end instants, and every `local` wall clock. | Europe/Copenhagen |
latitude | float | Observer latitude in decimal degrees, echoed as supplied. | 55.6761 |
longitude | float | Observer longitude in decimal degrees, echoed as supplied. | 12.5683 |
moonrise | object | First moonrise inside the local date — the Moon's upper limb apparently touching the horizon. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`), `azimuthDegrees` (compass bearing at the crossing, 0° = north increasing clockwise) and `reason`. On an ordinary date `reason` is null; when the event does not happen all three others are null and `reason` is `crossing-falls-on-another-date`, `above-horizon-all-day` or `below-horizon-all-day`. No placeholder time is ever substituted. | {"instant":"2026-07-29T19:35:56.000Z","local":"2026-07-29T21:35:56","azimuthDegrees":127.07,"reason":null} |
moonset | object | First moonset inside the local date. **May be earlier than `moonrise`**: on the example date the Moon set at 04:23 local and rose again at 21:35. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`), `azimuthDegrees` (compass bearing at the crossing, 0° = north increasing clockwise) and `reason`. On an ordinary date `reason` is null; when the event does not happen all three others are null and `reason` is `crossing-falls-on-another-date`, `above-horizon-all-day` or `below-horizon-all-day`. No placeholder time is ever substituted. | {"instant":"2026-07-29T02:23:54.000Z","local":"2026-07-29T04:23:54","azimuthDegrees":226.84,"reason":null} |
upperTransit | object | First upper meridian transit inside the local date: `{ instant, local, altitudeDegrees, reason }`, where `altitudeDegrees` is the topocentric geometric altitude at culmination (no refraction). Its UTC date can be the previous day, and the altitude can be negative — this endpoint publishes a transit that culminates below the horizon, which the USNO omits. `reason` is `crossing-falls-on-another-date` when the transit lands on a neighbouring local date, and then all three other members are null. | {"instant":"2026-07-28T22:48:09.000Z","local":"2026-07-29T00:48:09","altitudeDegrees":10.3,"reason":null} |
aboveHorizonSeconds | integer (0-172800) | Seconds inside this local civil date during which the Moon's upper limb is above the horizon, summed over every above-horizon interval, and never more than the length of the local date itself. **The upper bound is not 86400**: a local date is 23 or 25 hours long on a daylight-saving change, some zones shift by 30 or 45 minutes, and a historical date-line or standard-offset jump can make one local date far longer than a day — sweeping every IANA zone over 1900-2100 finds 150 such dates in 44 zones, the longest being Pacific/Kwajalein 1969-09-30 at 47 hours (169 200 s), where at a high enough latitude the Moon stays up for all of it. | 24478 |
illuminatedFractionAtTransit nullable | float (0 to 1) | Geocentric illuminated fraction at the instant of `upperTransit` — the observationally meaningful value for that night, and generally *not* the value at local noon that almanacs print for the date. `null` on a date with no upper transit. For any other anchor call /api/moon/phase with an explicit `at`. | 0.99533 |
extraEvents | object[] | Any *additional* rise, set or upper transit on the same local date beyond the first of each kind, chronologically: `{ type, instant, local }` with `type` one of `moonrise`, `moonset`, `upper-transit`. Empty on almost every date: from about 63° of latitude upward the daily retardation can put two events of the same kind inside one local date, which over the whole of 2026 happens on 2 dates at 63°N and 5 at 72°N. This is where they appear instead of being dropped. | [] |
date string (YYYY-MM-DD) The local civil date the results describe, in the resolved zone.
example: 2026-07-29
timezone string Canonical IANA id used to resolve the local date, its start and end instants, and every `local` wall clock.
example: Europe/Copenhagen
latitude float Observer latitude in decimal degrees, echoed as supplied.
example: 55.6761
longitude float Observer longitude in decimal degrees, echoed as supplied.
example: 12.5683
moonrise object First moonrise inside the local date — the Moon's upper limb apparently touching the horizon. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`), `azimuthDegrees` (compass bearing at the crossing, 0° = north increasing clockwise) and `reason`. On an ordinary date `reason` is null; when the event does not happen all three others are null and `reason` is `crossing-falls-on-another-date`, `above-horizon-all-day` or `below-horizon-all-day`. No placeholder time is ever substituted.
example: {"instant":"2026-07-29T19:35:56.000Z","local":"2026-07-29T21:35:56","azimuthDegrees":127.07,"reason":null}
moonset object First moonset inside the local date. **May be earlier than `moonrise`**: on the example date the Moon set at 04:23 local and rose again at 21:35. Object with `instant` (UTC ISO 8601, whole seconds), `local` (naive wall clock in `tz`), `azimuthDegrees` (compass bearing at the crossing, 0° = north increasing clockwise) and `reason`. On an ordinary date `reason` is null; when the event does not happen all three others are null and `reason` is `crossing-falls-on-another-date`, `above-horizon-all-day` or `below-horizon-all-day`. No placeholder time is ever substituted.
example: {"instant":"2026-07-29T02:23:54.000Z","local":"2026-07-29T04:23:54","azimuthDegrees":226.84,"reason":null}
upperTransit object First upper meridian transit inside the local date: `{ instant, local, altitudeDegrees, reason }`, where `altitudeDegrees` is the topocentric geometric altitude at culmination (no refraction). Its UTC date can be the previous day, and the altitude can be negative — this endpoint publishes a transit that culminates below the horizon, which the USNO omits. `reason` is `crossing-falls-on-another-date` when the transit lands on a neighbouring local date, and then all three other members are null.
example: {"instant":"2026-07-28T22:48:09.000Z","local":"2026-07-29T00:48:09","altitudeDegrees":10.3,"reason":null}
aboveHorizonSeconds integer (0-172800) Seconds inside this local civil date during which the Moon's upper limb is above the horizon, summed over every above-horizon interval, and never more than the length of the local date itself. **The upper bound is not 86400**: a local date is 23 or 25 hours long on a daylight-saving change, some zones shift by 30 or 45 minutes, and a historical date-line or standard-offset jump can make one local date far longer than a day — sweeping every IANA zone over 1900-2100 finds 150 such dates in 44 zones, the longest being Pacific/Kwajalein 1969-09-30 at 47 hours (169 200 s), where at a high enough latitude the Moon stays up for all of it.
example: 24478
illuminatedFractionAtTransit float (0 to 1) nullable Geocentric illuminated fraction at the instant of `upperTransit` — the observationally meaningful value for that night, and generally *not* the value at local noon that almanacs print for the date. `null` on a date with no upper transit. For any other anchor call /api/moon/phase with an explicit `at`.
example: 0.99533
extraEvents object[] Any *additional* rise, set or upper transit on the same local date beyond the first of each kind, chronologically: `{ type, instant, local }` with `type` one of `moonrise`, `moonset`, `upper-transit`. Empty on almost every date: from about 63° of latitude upward the daily retardation can put two events of the same kind inside one local date, which over the whole of 2026 happens on 2 dates at 63°N and 5 at 72°N. This is where they appear instead of being dropped.
example: []
/api/moon/times?lat=55.6761&lng=12.5683&date=2026-07-29&tz=Europe/Copenhagen {
"data": {
"date": "2026-07-29",
"timezone": "Europe/Copenhagen",
"latitude": 55.6761,
"longitude": 12.5683,
"moonrise": {
"instant": "2026-07-29T19:35:56.000Z",
"local": "2026-07-29T21:35:56",
"azimuthDegrees": 127.07,
"reason": null
},
"moonset": {
"instant": "2026-07-29T02:23:54.000Z",
"local": "2026-07-29T04:23:54",
"azimuthDegrees": 226.84,
"reason": null
},
"upperTransit": {
"instant": "2026-07-28T22:48:09.000Z",
"local": "2026-07-29T00:48:09",
"altitudeDegrees": 10.3,
"reason": null
},
"aboveHorizonSeconds": 24478,
"illuminatedFractionAtTransit": 0.99533,
"extraEvents": []
},
"meta": {
"endpoint": "moon",
"route": "/times",
"params": {
"lat": 55.6761,
"lng": 12.5683,
"date": "2026-07-29",
"tz": "Europe/Copenhagen"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/times?lat=55.6761&lng=12.5683&date=2026-08-08&tz=Europe/Copenhagen {
"data": {
"date": "2026-08-08",
"timezone": "Europe/Copenhagen",
"latitude": 55.6761,
"longitude": 12.5683,
"moonrise": {
"instant": null,
"local": null,
"azimuthDegrees": null,
"reason": "crossing-falls-on-another-date"
},
"moonset": {
"instant": "2026-08-08T16:42:15.000Z",
"local": "2026-08-08T18:42:15",
"azimuthDegrees": 326.02,
"reason": null
},
"upperTransit": {
"instant": "2026-08-08T06:54:14.000Z",
"local": "2026-08-08T08:54:14",
"altitudeDegrees": 61.48,
"reason": null
},
"aboveHorizonSeconds": 67335,
"illuminatedFractionAtTransit": 0.25871,
"extraEvents": []
},
"meta": {
"endpoint": "moon",
"route": "/times",
"params": {
"lat": 55.6761,
"lng": 12.5683,
"date": "2026-08-08",
"tz": "Europe/Copenhagen"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/times?lat=69.6492&lng=18.9553&date=2026-07-27&tz=Europe/Oslo {
"data": {
"date": "2026-07-27",
"timezone": "Europe/Oslo",
"latitude": 69.6492,
"longitude": 18.9553,
"moonrise": {
"instant": null,
"local": null,
"azimuthDegrees": null,
"reason": "below-horizon-all-day"
},
"moonset": {
"instant": null,
"local": null,
"azimuthDegrees": null,
"reason": "below-horizon-all-day"
},
"upperTransit": {
"instant": "2026-07-27T21:32:25.000Z",
"local": "2026-07-27T23:32:25",
"altitudeDegrees": -6.66,
"reason": null
},
"aboveHorizonSeconds": 0,
"illuminatedFractionAtTransit": 0.97181,
"extraEvents": []
},
"meta": {
"endpoint": "moon",
"route": "/times",
"params": {
"lat": 69.6492,
"lng": 18.9553,
"date": "2026-07-27",
"tz": "Europe/Oslo"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/times?lat=-33.8688&lng=151.2093&tz=Australia/Sydney {
"data": {
"date": "2026-07-31",
"timezone": "Australia/Sydney",
"latitude": -33.8688,
"longitude": 151.2093,
"moonrise": {
"instant": "2026-07-31T08:47:57.000Z",
"local": "2026-07-31T18:47:57",
"azimuthDegrees": 104.72,
"reason": null
},
"moonset": {
"instant": "2026-07-30T21:41:04.000Z",
"local": "2026-07-31T07:41:04",
"azimuthDegrees": 252.31,
"reason": null
},
"upperTransit": {
"instant": "2026-07-30T14:48:43.000Z",
"local": "2026-07-31T00:48:43",
"altitudeDegrees": 71.95,
"reason": null
},
"aboveHorizonSeconds": 46387,
"illuminatedFractionAtTransit": 0.99006,
"extraEvents": []
},
"meta": {
"endpoint": "moon",
"route": "/times",
"params": {
"lat": -33.8688,
"lng": 151.2093,
"tz": "Australia/Sydney",
"date": "2026-07-31"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} at is an absolute instant; omit it for now. Altitude is topocentric and geometric — parallax for the observer's position on the WGS 84 ellipsoid is applied, atmospheric refraction is not.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
lat
required
| float | allowed: -90 – 90 example: 55.6761 | Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90). |
lng
required
| float | allowed: -180 – 180 example: 12.5683 | Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180). |
at | date | example: 2026-07-29T00:00:00Z | Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now. |
tz | string | default: UTC example: Europe/Copenhagen | IANA zone used only to render `localTime`, case-insensitive. It does not move the instant; unknown ids return a 400. |
lat float required Observer latitude in WGS 84 decimal degrees, positive north (−90 to 90).
lng float required Observer longitude in WGS 84 decimal degrees, positive east (−180 to 180).
at date Absolute instant: YYYY-MM-DD (UTC midnight) or RFC 3339 with Z or an explicit offset, resolved year 1900–2100. Defaults to now.
tz string IANA zone used only to render `localTime`, case-insensitive. It does not move the instant; unknown ids return a 400.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
fields | list | example: at,timezone | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: aboveHorizon | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
at | string (ISO 8601 UTC) | The evaluated instant in UTC. | 2026-07-29T00:00:00.000Z |
timezone | string | Canonical IANA id used to render `localTime`. It does not move the instant. | Europe/Copenhagen |
localTime | string (YYYY-MM-DDTHH:mm:ss) | Naive local wall clock of the same instant. | 2026-07-29T02:00:00 |
latitude | float | Observer latitude, echoed as supplied. | 55.6761 |
longitude | float | Observer longitude, echoed as supplied. | 12.5683 |
altitudeDegrees | float (-90 to 90) | Topocentric geometric altitude of the Moon's centre above the true horizon. No refraction correction, so near the horizon the apparent Moon sits roughly 0.57° higher. Observer elevation is taken as sea level. | 9.0873 |
azimuthDegrees | float (0 to 360) | Compass bearing, 0° = north increasing clockwise. Within a hair of the zenith or of a pole the bearing is geometrically undefined and the meridian convention is reported instead: 180 for an observer north of the equator, 0 otherwise — the same convention /api/sun uses. | 196.2188 |
rightAscensionDegrees | float (0 to 360) | Apparent topocentric right ascension, referred to the **true equator and equinox of date**. Not the ICRF/J2000 value — comparing it against an astrometric ICRF ephemeris shows the accumulated precession, not an error. | 301.6825 |
declinationDegrees | float (-90 to 90) | Apparent topocentric declination, true equator of date. | -23.8409 |
distanceKm | float | Topocentric centre-to-centre distance in km — up to about 6 400 km shorter than the geocentric distance /api/moon/phase reports, because the observer is off the Earth's centre. | 400076.5 |
horizontalParallaxDegrees | float | Geocentric horizontal parallax of the Moon — `asin(6378.137 km / distance)` on the WGS 84 equatorial radius. Measured over 2026-2036 it ranges 0.8987° to 1.0253°. | 0.911 |
apparentDiameterDegrees | float | Topocentric apparent angular diameter of the lunar disk. | 0.4976 |
parallacticAngleDegrees | float (-180 to 180) | Angle at the Moon between the direction to the celestial north pole and the direction to the zenith. Implementations disagree on the sign, so the convention here is stated operationally: `atan2(cos φ · sin H, sin φ · cos δ − cos φ · sin δ · cos H)` with H the local hour angle — 0 at upper transit for an object south of the zenith, positive after transit (object west of the meridian), and ±180 near lower transit. | 9.9148 |
hourAngleDegrees | float (-180 to 180) | Local apparent hour angle of the Moon: 0 at upper transit, negative before it, positive after. It advances at about 14.49° per hour, not 15° — the Moon's own eastward motion is subtracted. | 17.5494 |
aboveHorizon | boolean | True when the Moon's upper limb is above the horizon by the *same* definition /api/moon/times uses for moonrise and moonset, so the two routes always agree. | true |
at string (ISO 8601 UTC) The evaluated instant in UTC.
example: 2026-07-29T00:00:00.000Z
timezone string Canonical IANA id used to render `localTime`. It does not move the instant.
example: Europe/Copenhagen
localTime string (YYYY-MM-DDTHH:mm:ss) Naive local wall clock of the same instant.
example: 2026-07-29T02:00:00
latitude float Observer latitude, echoed as supplied.
example: 55.6761
longitude float Observer longitude, echoed as supplied.
example: 12.5683
altitudeDegrees float (-90 to 90) Topocentric geometric altitude of the Moon's centre above the true horizon. No refraction correction, so near the horizon the apparent Moon sits roughly 0.57° higher. Observer elevation is taken as sea level.
example: 9.0873
azimuthDegrees float (0 to 360) Compass bearing, 0° = north increasing clockwise. Within a hair of the zenith or of a pole the bearing is geometrically undefined and the meridian convention is reported instead: 180 for an observer north of the equator, 0 otherwise — the same convention /api/sun uses.
example: 196.2188
rightAscensionDegrees float (0 to 360) Apparent topocentric right ascension, referred to the **true equator and equinox of date**. Not the ICRF/J2000 value — comparing it against an astrometric ICRF ephemeris shows the accumulated precession, not an error.
example: 301.6825
declinationDegrees float (-90 to 90) Apparent topocentric declination, true equator of date.
example: -23.8409
distanceKm float Topocentric centre-to-centre distance in km — up to about 6 400 km shorter than the geocentric distance /api/moon/phase reports, because the observer is off the Earth's centre.
example: 400076.5
horizontalParallaxDegrees float Geocentric horizontal parallax of the Moon — `asin(6378.137 km / distance)` on the WGS 84 equatorial radius. Measured over 2026-2036 it ranges 0.8987° to 1.0253°.
example: 0.911
apparentDiameterDegrees float Topocentric apparent angular diameter of the lunar disk.
example: 0.4976
parallacticAngleDegrees float (-180 to 180) Angle at the Moon between the direction to the celestial north pole and the direction to the zenith. Implementations disagree on the sign, so the convention here is stated operationally: `atan2(cos φ · sin H, sin φ · cos δ − cos φ · sin δ · cos H)` with H the local hour angle — 0 at upper transit for an object south of the zenith, positive after transit (object west of the meridian), and ±180 near lower transit.
example: 9.9148
hourAngleDegrees float (-180 to 180) Local apparent hour angle of the Moon: 0 at upper transit, negative before it, positive after. It advances at about 14.49° per hour, not 15° — the Moon's own eastward motion is subtracted.
example: 17.5494
aboveHorizon boolean True when the Moon's upper limb is above the horizon by the *same* definition /api/moon/times uses for moonrise and moonset, so the two routes always agree.
example: true
/api/moon/position?lat=55.6761&lng=12.5683&at=2026-07-29T00:00:00Z&tz=Europe/Copenhagen {
"data": {
"at": "2026-07-29T00:00:00.000Z",
"timezone": "Europe/Copenhagen",
"localTime": "2026-07-29T02:00:00",
"latitude": 55.6761,
"longitude": 12.5683,
"altitudeDegrees": 9.0873,
"azimuthDegrees": 196.2188,
"rightAscensionDegrees": 301.6825,
"declinationDegrees": -23.8409,
"distanceKm": 400076.5,
"horizontalParallaxDegrees": 0.911,
"apparentDiameterDegrees": 0.4976,
"parallacticAngleDegrees": 9.9148,
"hourAngleDegrees": 17.5494,
"aboveHorizon": true
},
"meta": {
"endpoint": "moon",
"route": "/position",
"params": {
"lat": 55.6761,
"lng": 12.5683,
"at": "2026-07-29",
"tz": "Europe/Copenhagen"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/position?lat=69.6492&lng=18.9553&at=2026-07-29T21:56:00Z&tz=Europe/Oslo {
"data": {
"at": "2026-07-29T21:56:00.000Z",
"timezone": "Europe/Oslo",
"localTime": "2026-07-29T23:56:00",
"latitude": 69.6492,
"longitude": 18.9553,
"altitudeDegrees": -0.8195,
"azimuthDegrees": 163.3569,
"rightAscensionDegrees": 313.296,
"declinationDegrees": -20.2779,
"distanceKm": 398815.1,
"horizontalParallaxDegrees": 0.9164,
"apparentDiameterDegrees": 0.4992,
"parallacticAngleDegrees": -6.0954,
"hourAngleDegrees": -17.7763,
"aboveHorizon": false
},
"meta": {
"endpoint": "moon",
"route": "/position",
"params": {
"lat": 69.6492,
"lng": 18.9553,
"at": "2026-07-29T21:56:00.000Z",
"tz": "Europe/Oslo"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/position?lat=-33.8688&lng=151.2093&tz=Australia/Sydney {
"data": {
"at": "2026-07-30T15:14:08.000Z",
"timezone": "Australia/Sydney",
"localTime": "2026-07-31T01:14:08",
"latitude": -33.8688,
"longitude": 151.2093,
"altitudeDegrees": 71.0101,
"azimuthDegrees": 341.2164,
"rightAscensionDegrees": 321.7682,
"declinationDegrees": -15.7337,
"distanceKm": 390667.1,
"horizontalParallaxDegrees": 0.9212,
"apparentDiameterDegrees": 0.5096,
"parallacticAngleDegrees": 163.8732,
"hourAngleDegrees": 6.2494,
"aboveHorizon": true
},
"meta": {
"endpoint": "moon",
"route": "/position",
"params": {
"lat": -33.8688,
"lng": 151.2093,
"tz": "Australia/Sydney",
"at": "2026-07-30T15:14:08.000Z"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} year selects by the local civil year in tz, so tz genuinely changes which instants are in scope near 1 January. Omit year for the current year in that zone. count acts as a limit only — a year holds 49 or 50 primary phases.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
year | int | allowed: 1900 – 2100 example: 2026 | Local civil year in the resolved zone (1900–2100). Defaults to the current year in that zone. |
phase | enum | allowed: new | first-quarter | full | last-quarter example: full | Keep only one of the four primary phases, matched case-insensitively. Omit for all four. |
tz | string | default: UTC example: Europe/Copenhagen | IANA zone that selects the civil year and renders every `local` wall clock, case-insensitive. Unknown ids return a 400. |
year int Local civil year in the resolved zone (1900–2100). Defaults to the current year in that zone.
phase enum Keep only one of the four primary phases, matched case-insensitively. Omit for all four.
tz string IANA zone that selects the civil year and renders every `local` wall clock, case-insensitive. Unknown ids return a 400.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
count | int | default: all matches allowed: 1 – 100 example: 3 | Limit the number of returned records (1–100). Defaults to all matches. |
fields | list | example: phase,instant | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: deltaTSeconds | Return all fields except these (comma-separated). |
format | enum | default: json allowed: json | ndjson | csv example: csv | Response format: json envelope, ndjson (one record per line) or csv. |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
count int Limit the number of returned records (1–100). Defaults to all matches.
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
format enum Response format: json envelope, ndjson (one record per line) or csv.
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
phase | string | One of `new`, `first-quarter`, `full` or `last-quarter`. | full |
instant | string (ISO 8601 UTC) | The exact instant of the phase in UTC, rounded to the second. | 2026-07-29T14:35:36.000Z |
local | string (YYYY-MM-DDTHH:mm:ss) | Naive local wall clock of the same instant in `tz`. | 2026-07-29T16:35:36 |
localDate | string (YYYY-MM-DD) | The local civil date in `tz` the instant falls on — the value `year` filters against. | 2026-07-29 |
lunationNumber | integer | Brown Lunation Number of the cycle this phase belongs to (lunation 1 began at the new moon of 1923 January 17). All four phases of one cycle share it. | 1281 |
deltaTSeconds | float | The TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable. | 75.4 |
phase string One of `new`, `first-quarter`, `full` or `last-quarter`.
example: full
instant string (ISO 8601 UTC) The exact instant of the phase in UTC, rounded to the second.
example: 2026-07-29T14:35:36.000Z
local string (YYYY-MM-DDTHH:mm:ss) Naive local wall clock of the same instant in `tz`.
example: 2026-07-29T16:35:36
localDate string (YYYY-MM-DD) The local civil date in `tz` the instant falls on — the value `year` filters against.
example: 2026-07-29
lunationNumber integer Brown Lunation Number of the cycle this phase belongs to (lunation 1 began at the new moon of 1923 January 17). All four phases of one cycle share it.
example: 1281
deltaTSeconds float The TT−UT offset applied to convert the Terrestrial-Time solve to UTC, so the conversion is auditable.
example: 75.4
/api/moon/phases?year=2026 {
"data": [
{
"phase": "full",
"instant": "2026-01-03T10:02:49.000Z",
"local": "2026-01-03T10:02:49",
"localDate": "2026-01-03",
"lunationNumber": 1274,
"deltaTSeconds": 75.1
},
{
"phase": "last-quarter",
"instant": "2026-01-10T15:48:18.000Z",
"local": "2026-01-10T15:48:18",
"localDate": "2026-01-10",
"lunationNumber": 1274,
"deltaTSeconds": 75.1
},
{
"phase": "new",
"instant": "2026-01-18T19:51:53.000Z",
"local": "2026-01-18T19:51:53",
"localDate": "2026-01-18",
"lunationNumber": 1275,
"deltaTSeconds": 75.1
},
{
"phase": "first-quarter",
"instant": "2026-01-26T04:47:17.000Z",
"local": "2026-01-26T04:47:17",
"localDate": "2026-01-26",
"lunationNumber": 1275,
"deltaTSeconds": 75.1
},
{
"phase": "full",
"instant": "2026-02-01T22:09:09.000Z",
"local": "2026-02-01T22:09:09",
"localDate": "2026-02-01",
"lunationNumber": 1275,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/phases?year=2026&phase=full&tz=Europe/Copenhagen {
"data": [
{
"phase": "full",
"instant": "2026-01-03T10:02:49.000Z",
"local": "2026-01-03T11:02:49",
"localDate": "2026-01-03",
"lunationNumber": 1274,
"deltaTSeconds": 75.1
},
{
"phase": "full",
"instant": "2026-02-01T22:09:09.000Z",
"local": "2026-02-01T23:09:09",
"localDate": "2026-02-01",
"lunationNumber": 1275,
"deltaTSeconds": 75.2
},
{
"phase": "full",
"instant": "2026-03-03T11:37:47.000Z",
"local": "2026-03-03T12:37:47",
"localDate": "2026-03-03",
"lunationNumber": 1276,
"deltaTSeconds": 75.2
},
{
"phase": "full",
"instant": "2026-04-02T02:11:51.000Z",
"local": "2026-04-02T04:11:51",
"localDate": "2026-04-02",
"lunationNumber": 1277,
"deltaTSeconds": 75.3
},
{
"phase": "full",
"instant": "2026-05-01T17:23:04.000Z",
"local": "2026-05-01T19:23:04",
"localDate": "2026-05-01",
"lunationNumber": 1278,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/moon/phases?phase=new {
"data": [
{
"phase": "new",
"instant": "2026-01-18T19:51:53.000Z",
"local": "2026-01-18T19:51:53",
"localDate": "2026-01-18",
"lunationNumber": 1275,
"deltaTSeconds": 75.1
},
{
"phase": "new",
"instant": "2026-02-17T12:01:03.000Z",
"local": "2026-02-17T12:01:03",
"localDate": "2026-02-17",
"lunationNumber": 1276,
"deltaTSeconds": 75.2
},
{
"phase": "new",
"instant": "2026-03-19T01:23:23.000Z",
"local": "2026-03-19T01:23:23",
"localDate": "2026-03-19",
"lunationNumber": 1277,
"deltaTSeconds": 75.2
},
{
"phase": "new",
"instant": "2026-04-17T11:51:42.000Z",
"local": "2026-04-17T11:51:42",
"localDate": "2026-04-17",
"lunationNumber": 1278,
"deltaTSeconds": 75.3
},
{
"phase": "new",
"instant": "2026-05-16T20:00:56.000Z",
"local": "2026-05-16T20:00:56",
"localDate": "2026-05-16",
"lunationNumber": 1279,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} Lunar phase, rise and set times and topocentric position, evaluated per request from the ELP-2000/82B lunar solution (Chapront-Touzé & Chapront) and VSOP87D (Bretagnon & Francou) — both published openly by the Bureau des Longitudes and distributed as CDS catalogues — with the IAU 1980 nutation series and the Espenak & Meeus ΔT polynomials. There is no ephemeris file to download, no upstream service that can go down, and no key.
/api/moon/phase — illuminated fraction, phase angle, elongation, lunar age, distance, Brown lunation number and the surrounding primary-phase instants at one instant./api/moon/times — moonrise, moonset and lunar transit on one local civil date, with honest nulls when an event does not happen./api/moon/position — topocentric altitude, azimuth, apparent right ascension and declination, distance, parallax and parallactic angle at an instant./api/moon/phases — every new moon, first quarter, full moon and last quarter of a year, with the exact instant and the lunation number.Successive moonrises are about 24 h 50 min apart, so the lunar day drifts against the civil calendar: roughly once a month a local civil date contains a moonset but no moonrise at all (or the reverse), and moonset is often earlier than moonrise in the same record. Copenhagen on 2026-08-08 is a worked example — the Moon sets at 18:42 local, transits at 08:54, and never rises; moonrise.instant is null and moonrise.reason is crossing-falls-on-another-date. The next date, 2026-08-09, has a rise at 00:10. Nothing is invented to fill the gap, and the two events are never sorted or swapped into a plausible-looking pair.
At high latitude the Moon can also stay below the horizon for a whole date while being nearly fully lit — Tromsø on 2026-07-27 has neither a rise nor a set with the disk 95 % illuminated (reason: "below-horizon-all-day") — or produce two rises or two sets on one date, which the retardation makes possible from about 63° of latitude upward. Those extras go in extraEvents rather than being dropped — though they are genuinely rare: sweeping every date of 2026 finds them on 2 dates at 63°N, 4 at 66.5°N and 5 at 72°N, and on none at all at 60° or below.
/times reports the events that genuinely fall inside the requested local civil date, which is what every almanac does. The date's start and end instants are found by bisecting the zone's own calendar, never by adding 24 hours — so a 23-hour daylight-saving day, a 30- or 45-minute offset (Lord Howe, Kathmandu, Chatham) and the zones whose transition happens at 00:00 local, where local midnight is skipped or repeated outright (Santiago, Havana), all come out right. It also survives the historical date-line and standard-offset jumps that make a local civil date much longer than a day: sweeping every IANA zone across 1900–2100 finds 150 local dates longer than 25 hours in 44 zones — Pacific/Kwajalein 1969-09-30 is 47 hours long (it skipped a day at the date line), America/Inuvik 1952-12-31 is 32 hours, Antarctica/Macquarie 1919-03-31 is 34 hours — and each is served with the events and the above-horizon total of that actual window. That is why aboveHorizonSeconds is documented as 0–172800 rather than 0–86400, and why the value is clamped to the real window length rather than to a nominal day.
Every number below was measured, not assumed, by scripts/refresh-moon.mjs --online against two US-government services:
| Compared against | Scope | Maximum difference |
|---|---|---|
| USNO published primary-phase instants | 247 instants across 1900, 1950, 2000, 2026 and 2050 | 43 s |
| USNO published primary-phase instants, past 2050 | 99 instants across 2075 and 2099 | 108 s (ΔT prediction, not the series) |
| USNO published moonrise / moonset / transit | 15 events, Copenhagen · Tromsø · New York · Sydney | 25 s |
| USNO published illuminated percentage | 7 dates, at local noon | 0.47 pp (USNO prints whole percents) |
| JPL Horizons (DE441) geocentric apparent longitude, at fixed Terrestrial Time | 110 007 epochs spanning 1900–2100, one every 16 hours | 1.82″ |
| JPL Horizons apparent ecliptic latitude | same | 0.88″ |
| JPL Horizons geometric geocentric distance | same | 1.59 km |
| JPL Horizons illuminated percentage | same | 0.0026 pp |
| JPL Horizons topocentric apparent RA / Dec / azimuth / elevation, at fixed UTC | 117 epochs, 1975 · 2026 · 2049 | 14.3″ / 5.2″ / 20.9″ / 9.9″ |
The count of primary phases in a year matched the USNO's exactly for every year tested. The fixed-Terrestrial-Time rows are a dense sweep of the whole window, not a hand-picked epoch list: an earlier revision of this page quoted a 14-epoch sample, whose maxima were 2–4× smaller and were not maxima at all.
The gap between the fixed-Terrestrial-Time figures (a couple of arcseconds) and the fixed-UTC ones (tens of arcseconds) is not the series: it is the disagreement between the Espenak & Meeus ΔT polynomials this endpoint uses and JPL's own ΔT. ΔT is observed in the past and predicted in the future, so the two models drift apart: about 7 s in 2026, 23 s in 2049 and 130 s by 2099. Phase instants therefore hold to well under a minute against the USNO through 2050 and widen to about two minutes near 2100 — the same caveat /api/sun/seasons carries. The ΔT actually applied is returned as deltaTSeconds on every phase object so the conversion is auditable.
The shipped tables are a documented truncation of the published series: 314 + 168 + 162 ELP terms in longitude, latitude and distance (every term with an amplitude of at least 0.03″ or 0.06 km, from the Main Problem plus the Earth-figure and planetary perturbations), 130 + 23 VSOP87D terms for the Sun and 36 nutation terms. The tidal, Moon-figure, relativistic and solar-eccentricity perturbation families are dropped whole; measured over 1900–2100 they contribute at most 0.009″. Relative to the same series evaluated in full the truncation costs 0.911″ of longitude and 1.3999 km of distance. Not one coefficient is hand-typed: every upstream file is pinned by SHA-256 and re-parsed by scripts/refresh-moon.mjs --write, whose parser re-emits each record in the authors' own Fortran format and fails on the first row that does not round-trip.
Rise and set use the apparent contact of the Moon's upper limb with the horizon: topocentric geometric altitude of the centre at −(0.5667° + 0.2725·π), where π is the horizontal parallax at that instant, so the threshold swings between about −0.812° and −0.846° rather than being a constant. (That is algebraically the classical geocentric form 0.7275·π − 34′ with the parallax moved onto the position instead of the threshold; the constant geocentric value usually quoted is +0.125°.) /position's aboveHorizon uses the identical expression, so the two routes provably agree at every crossing. Crossings are found by scanning the local date's altitude every 10 minutes and refining each sign change to under half a second: over 10 minutes the Moon's altitude moves at most about 2.6°, so only a grazing extremum within a few hundredths of a degree of the threshold could hide a pair of crossings.
/api/moon/times publishes an upper transit even when the Moon culminates below the horizon, because the transit genuinely happens and its altitude is reported. The USNO omits those, so on a date like Tromsø 2026-07-29 this endpoint returns a transit where their table shows only a rise. That is a deliberate difference in what is published, not a difference in the numbers.
phaseName is this API's convention, not a standard: eight 45°-wide sectors of elongationDegrees centred on the four primary instants (new is 337.5°–360° and 0°–22.5°, waxing-crescent 22.5°–67.5°, and so on). Other publishers bin differently, so near a boundary a name can disagree with theirs — the USNO still says "Waxing Gibbous" where these sectors have already switched to full. nextPrimaryPhase and /api/moon/phases carry the exact instants, which is what to compare.
Eclipses (contact times need Besselian elements and node precision a truncated series does not deliver). Perigee and apogee instants — distanceKm is returned, the instants are a separate series and are not claimed. "Supermoon", "blue moon", "harvest moon", "micromoon" — popular-media labels with no standards body behind them, left out for the same reason /api/sun leaves out golden hour. Lunar-calendar month starts, Hijri dates, Ramadan and Easter's lunar rule — an astronomical phase instant is not a calendrical month start, which depends on jurisdiction-specific crescent-visibility criteria or local sighting; that is exactly why /api/holidays still documents partial calendars, and this endpoint does not change it. Tides. Libration, position angle of the axis, selenographic coordinates and terminator geometry. Atmospheric refraction on /position — altitudeDegrees is geometric, and only the fixed 34′ of mean refraction baked into the rise/set threshold is modelled. Observer elevation, the local horizon profile, pressure and temperature — sea level and standard conditions only. Astrology — no moon signs, houses or void-of-course. And UT1−UTC (under 0.9 s, unpredictable) is not modelled, so every instant is UTC treated as UT.
The illuminated fraction and phase angle are geocentric. Measured against JPL Horizons, a topocentric observer's illuminated fraction differs from the geocentric one by up to about 0.7 percentage points near the horizon, and that difference is not modelled.
These values are not suitable for navigational, legal or safety-critical use — use a national almanac office for that.
Every route is limited to years 1900–2100; anything outside returns a 400 rather than an unfitted extrapolation.
Call /api/moon/phase?tz=Europe/Copenhagen. It returns illuminatedFraction, phaseAngleDegrees, elongationDegrees, phaseName and ageDays for the instant you ask about (now, if you omit at), plus the geocentric distance and the surrounding primary-phase instants. No key, no signup, no quota form.
Because on roughly one date a month the Moon genuinely does not rise on that calendar date — successive moonrises are about 24 h 50 min apart, so the lunar day drifts against the civil one. Copenhagen on 2026-08-08 is a real example: the Moon sets at 18:42 local and transits at 08:54, and there is no moonrise at all, so moonrise.instant is null and moonrise.reason is crossing-falls-on-another-date. A placeholder time is never substituted.
/api/moon/phase returns nextFullMoon as an exact UTC instant plus the local wall clock in your tz. For a whole year at once, /api/moon/phases?year=2026&phase=full lists every full moon; drop phase to get all 49 or 50 primary phases of the year.
Measured, not estimated: against the U.S. Naval Observatory's published times the worst difference over the reference set (Copenhagen, Tromsø, New York, Sydney) is 25 seconds, and primary-phase instants agree to within 43 seconds over 247 instants across 1900, 1950, 2000, 2026 and 2050. Against JPL Horizons at fixed Terrestrial Time, over 110 007 epochs spanning 1900–2100, one every 16 hours, the apparent lunar longitude holds to 1.82 arcseconds and the geocentric distance to 1.59 km. Accuracy widens to about two minutes near 2100 (108 s worst case over 99 instants across 2075 and 2099), where ΔT is a prediction rather than an observation, and grazing events, observer elevation, the local horizon profile and non-standard refraction are not modelled.
No. It computes astronomical phase instants; the start of a lunar or Hijri month depends on jurisdiction-specific crescent-visibility criteria or on local sighting, which is a different question. That is also why /api/holidays still documents partial calendars for some countries — this endpoint does not change that.
Sunrise, sunset, solar noon, day length, the three twilights and solar elevation/azimuth for any coordinate and date, from the NOAA equations.
Magnetic declination, inclination and field strength anywhere on Earth from the official WMM2025 coefficients, plus compass-to-true heading conversion.
Live IANA offsets, DST transitions, local-time ambiguity resolution and exact instant conversion — no guessed wall-clock mappings.
Real calendar facts for any date — weekday, ISO week, day of year, quarter, leap year, days in month, weekend flag and Unix timestamp. Defaults to today.
Real public holidays for 61 countries, computed from official national rules — list a year, check a date, or get the next upcoming holiday.
Convert one instant between Unix s/ms/µs/ns, ISO 8601, Windows FILETIME, .NET ticks, Excel serials, Cocoa, HFS+, NTP and Julian Day — exactly.