Astro version 2.11.0

This is the changelog for Astro version 2.11.0, released on November 1st, 2026. For older changelogs please consult the release tag on GitHub

Added

  • Astro.solar_eclipse_path/2 also bounds the region where the partial eclipse is seen: the penumbral limits, the sunrise and sunset limits, the curves of maximum eclipse at sunrise and sunset, and first and last contact. First and last contact agree with NASA's within 0.3 s.

Changed

  • Astro.solar_eclipse_path/2 returns the region of partial eclipse for a partial eclipse, with an empty central line and umbral limits, where it returned {:error, :no_path}.

Astro version 2.10.0

This is the changelog for Astro version 2.10.0, released on November 1st, 2026. For older changelogs please consult the release tag on GitHub

Added

  • Solar and lunar eclipses have a :saros field, their Saros series as NASA's catalogues number it (Astro.Saros); it matches NASA for all 1,397 eclipses of the six centuries tested.

  • Astro.Lunar.lunation_at/1 returns the lunation in progress at a moment, numbered as Meeus and NASA number them from the new moon of 6 January 2000.

  • Astro.Time.mean_synodic_month/0 and mean_tropical_year/0 are documented as public API.

  • Astro.solar_eclipse_path/2 returns a solar eclipse's central line and northern and southern limits as timed Geo.Points, with path width, duration and Sun altitude on the central line, for drawing the path on a map. Within 0.7 km of NASA's path tables where the Sun is 20° or more up.

  • Astro.solar_eclipse_at/3 and lunar_eclipse_at/3 return an eclipse's local circumstances: contacts, maximum, magnitude and obscuration for the Sun, and the Sun's or the Moon's altitude at each contact, or {:error, :not_visible}. Solar contacts match the USNO's to 2 s.

  • Astro.solar_eclipse_at_or_after/1 and solar_eclipse_before/1 return a solar eclipse's type (partial, annular, total or hybrid), gamma, magnitude and greatest eclipse, from Besselian elements; they match NASA's catalogue to 0.6 s over 1901–2100.

  • Astro.lunar_eclipse_at_or_after/2 and lunar_eclipse_before/2 return a lunar eclipse's type, gamma, magnitudes, greatest eclipse and contacts, matching NASA's catalogue to seconds over 1901–2100. The :shadow option chooses Danjon's (default) or Chauvenet's shadow enlargement.

  • Astro.Solar.analytical_solar_position/1 and analytical_solar_ecliptic_position/1 give the apparent Sun from analytical series for any date, within about 1″ RMS of JPL DE440s over 1900–2100.

  • Astro.Lunar.analytical_lunar_position/1 and analytical_lunar_ecliptic_position/1 give the apparent Moon from the Meeus chapter 47 series for any date, within about 3″ RMS of JPL DE440s over 1900–2100.

  • Astro.Coordinates.ecliptic_to_equatorial/3 converts ecliptic longitude and latitude to right ascension and declination.

  • Astro.Time.offset_from_longitude/1 accepts a Geo.Point as well as a Geo.PointZ or a number.

  • Astro.first_visible_crescent_on_or_before/4 and first_visible_crescent_on_or_after/4 return the evening a lunation's new crescent is first seen, for calendars whose months begin at first sighting; new_visible_crescent/4 takes options for every method, including :utc_offset.

  • Astro.sunrise/3, sunset/3, moonrise/3 and moonset/3 take :utc_offset, choosing the event on the local day at that offset (west of Greenwich a local evening's sunset is the next UTC day), and the Sun's take limb: :center, the Sun's centre on the horizon.

  • Astro.Solar.solar_longitude_day_on_or_after/3 and solar_longitude_day_on_or_before/3 return the local day the Sun reaches a longitude, such as a solar term or the December solstice, deciding the day from the Sun's rate; about 15 times faster than finding the moment.

  • Astro.Lunar.new_moon_day_before/2 and new_moon_day_on_or_after/2 return the local day of a new moon for an offset or an offset function, refining only new moons near local midnight; about twice as fast as the moment searches.

  • Astro.Solar.solar_noon/2 returns the moment the Sun's local hour angle is zero, found by Newton's method from 12:00 local mean time.

Changed

  • Astro.Time.delta_t/1 uses the Espenak and Meeus polynomials (NASA's eclipse model) before 1972 and joins the 2025 IERS value to the long-term parabola by 2150. Times move by up to 20 minutes around 250 CE and 70 minutes at 3000, and by under 2 s from 1700 to 2050.

  • The new moon searches refine only the lunation they need, and the lunar phase outside the ephemeris computes only the Moon's longitude: a new moon search takes about 40 µs near the present and 55 µs in 1200, where it took 73 and 194 µs.

  • The new moon and lunar phase searches end within a millisecond of the crossing, where the phase searches stopped within 0.43 s, so the three new moon searches agree to a millisecond.

  • The Astro new moon and lunar phase searches return {:error, :year_out_of_range} more than 50,000 years from J2000, as equinoxes and solstices do; the Astro.Lunar new moon searches raise ArgumentError there. 2.9.0 answered from chapter 49 alone to about ±300,000 years.

  • New moons are the moments the lunar phase passes 0°, refined from the Meeus chapter 49 estimate by the secant method, where chapter 49 alone was up to 17 s from JPL. Far from the present they follow the analytical series, which drift from chapter 49 by about 1 s per century².

  • Astro.equinox/3 and Astro.solstice/3 are the moments the Sun's apparent longitude reaches 0°, 90°, 180° or 270°: within a second of Meeus's full VSOP87 time for the June 1962 solstice, against 26 s for the Meeus closed form. They work for any year within 50,000 years of 2000, where 2.9.0 allowed 1000 to 3000, and the search ends within a millisecond rather than 0.86 s.

  • Dates outside the loaded ephemeris are answered from the analytical series: the Astro functions, sunrise and sunset, moonrise and moonset and crescent visibility no longer return {:error, :not_found}, and their specs no longer name it.

  • The positions, ecliptic coordinates, distance, altitude and phase in Astro.Solar and Astro.Lunar come from the analytical series where the loaded ephemeris does not cover the moment, where they raised MatchError. Astro.Solar.solar_ecliptic_longitude/1's fallback is now accurate to about 1″ near the present rather than 0.01°.

  • Astro.Solar.sun_geometric_mean_anomaly/1, earth_orbit_eccentricity/1 and sun_equation_of_center/1, and Astro.Lunar.mean_lunar_ecliptic_longitude/1 and lunar_elongation/1 are no longer deprecated: the analytical series are built from them.

Bug Fixes

  • Astro.solar_noon/2 evaluated the equation of time twelve hours early, so it was up to 18 s from the meridian transit. It is now the transit itself, to the microsecond rather than the second.

  • The Astro functions that return {:ok, _} or {:error, _} raised for an invalid location, date, options, phase, method, time zone resolver or database, or when no tz_world backend was running. They return an error such as {:error, :invalid_location} or {:error, :tz_world_backend_not_running}.

  • Astro.date_time_lunar_phase_at_or_before/2 and _at_or_after/2 return {:error, :invalid_phase} for a phase outside 0° to 360°, which was taken modulo 360°.

  • Astro.equinox/3 and Astro.solstice/3 raised FunctionClauseError for a non-integer year or an unknown event; they return {:error, :invalid_year} or {:error, :invalid_event}.

  • Astro.sun_azimuth_elevation/2 used mean rather than apparent sidereal time, so its azimuth was about 0.3′ from NREL's solar position algorithm; it now agrees to 0.05″.

  • Astro.Solar.solar_noon_utc/2 took west longitudes as positive, against its documentation, and equation_of_time/1 omitted Meeus chapter 28's aberration and nutation terms.

  • Astro.Lunar.lunar_phase_at/1 returned the chapter 49 estimate instead of the computed phase near every new moon, because its check for a large difference compared 359.9° with 0.1° as 359.8° apart.

  • The precession applied to JPL positions took the epoch terms of Meeus 21.2 as its t² and t³ coefficients, misplacing the Sun and Moon by up to about 2″ at 1900 and 2100. Rise and set times near the present move by milliseconds.

Astro version 2.9.0

This is the changelog for Astro version 2.9.0, released on October 26th, 2026. For older changelogs please consult the release tag on GitHub

Added

  • An application can supervise Astro itself: with the dependency marked runtime: false, so the :astro application is not started, listing Astro.Supervisor in the application's own tree loads the JPL ephemeris before the supervisor starts, where only the :astro application loaded it. Where the :astro application runs as well, the ephemeris it loaded is kept, so an application that lists Astro.Supervisor for tz_world's backend is unaffected. Astro.Supervisor describes the setup, and the astro: :load a release then needs.

Changed

  • JPL positions and the functions built on them are faster, with results unchanged to the last bit:
    • Astro.Ephemeris.check_coverage/1,2 looks up the ephemeris segments a moment needs, where it computed the Sun's and the Moon's apparent positions (47 µs to 4 µs for a span). Every function that checks coverage first gains: Astro.solar_noon/2 92 µs to 49 µs, Astro.lunar_phase_at/1 109 µs to 53 µs, Astro.sun_position_at/1 74 µs to 26 µs.

    • An ecliptic position of the Sun or the Moon computes the nutation once, where it computed it twice (Astro.Solar.solar_ecliptic_longitude/1 19 µs to 14 µs).

    • Sunrise, sunset, moonrise and moonset sample their search window only until the event is bracketed, where they sampled all of it (Astro.new_visible_crescent/3 6.0 ms to 4.1 ms).

Astro version 2.8.0

This is the changelog for Astro version 2.8.0, released on October 23rd, 2026. For older changelogs please consult the release tag on GitHub

Added

Breaking Changes

  • Astro.lunar_phase_at/1, illuminated_fraction_of_moon_at/1, date_time_new_moon_nearest/1, date_time_lunar_phase_at_or_before/2, date_time_lunar_phase_at_or_after/2, sun_position_at/1, moon_position_at/1, sun_apparent_longitude/1, sun_azimuth_elevation/2 and solar_noon/2 return {:error, :not_found} for dates the loaded ephemeris does not cover (1900–2100 for the bundled file), where 2.7.0 returned a value from the Meeus series.

Changed

  • Solar and lunar positions, ecliptic longitudes, latitudes and distances in Astro.Solar, Astro.Lunar and Astro.Lunar.CrescentVisibility are computed from the JPL DE440s ephemeris instead of the Meeus series. Results shift by seconds of arc; event times by seconds.

  • Astro.Solar.solar_ecliptic_longitude/1, and so solar_ecliptic_longitude_after/2 and estimate_prior_solar_ecliptic_longitude/2, fall back to the Meeus series for a moment the loaded ephemeris does not cover, where 2.8.0 raised MatchError. Lunisolar calendars find their solar terms for any era again.

Deprecated

  • Astro.Solar.sun_apparent_longitude/1, sun_true_longitude/1 and solar_declination/1 now use the JPL ephemeris; use solar_ecliptic_longitude/1 and solar_position/1, which take a moment.

  • Astro.Solar.obliquity_correction/1 and mean_obliquity_of_ecliptic/1 now use the IAU 1980 nutation; use Astro.Earth.nutation/1.

  • Astro.Solar.sun_equation_of_center/1, sun_geometric_mean_anomaly/1, earth_orbit_eccentricity/1, and Astro.Lunar.mean_lunar_ecliptic_longitude/1 and lunar_elongation/1 are unchanged and will be removed in Astro 3.0.

Bug Fixes

  • JPL nutation was rotated in the wrong sense, misplacing the Sun and Moon by up to ~30″ and shifting rise and set times by a few seconds. JPL-based equinox instants now match published values to within ~5 seconds.

  • The geocentric Sun added the Earth's offset from the Earth–Moon barycentre instead of subtracting it, an error of up to ~9,000 km in solar distance.

  • JPL positions are corrected for light time and aberration, so they are apparent rather than geometric positions, as documented.

Astro version 2.7.0

This is the changelog for Astro version 2.7.0, released on September 25th, 2026. For older changelogs please consult the release tag on GitHub

Enhancements

  • Astro.Lunar.date_time_new_moon_before/1 and date_time_new_moon_at_or_after/1 evaluate only the two lunations either side of the moment, about five times faster. Results are unchanged, bit for bit.

  • Astro.Time.dynamical_from_universal/1 and universal_from_dynamical/1 find the ΔT decimal year with integer day arithmetic, about 1.6 times faster. Results are unchanged on every day of years −9999 to 9999.

  • Astro.equinox/3 and Astro.solstice/3 take :time_zone (:utc by default, or a zone name) and :time_zone_database options and return the instant in that zone, whose civil date can differ from the UTC date — for Japan's equinox holidays, in about a third of years. A named zone with no time zone database configured returns {:error, :utc_only_time_zone_database}.

  • Astro.Supervisor.child_spec/1 lets Astro.Supervisor, which starts the tz_world backend, be listed as a child in an application's supervision tree.

Bug Fixes

  • The specs of Astro.date_time_new_moon_before/1, date_time_new_moon_nearest/1, date_time_new_moon_at_or_after/1, date_time_lunar_phase_at_or_before/2 and date_time_lunar_phase_at_or_after/2 were malformed, so their error return was silently dropped and dialyzer took them never to fail. With the fix below they cannot fail, so they declare {:ok, DateTime.t()} and their docs no longer describe an error shape they never returned.

  • Astro.Time.date_time_from_moment/1, and so every date-time search above, converts instants before 0000-01-01 instead of returning {:error, :invalid_time} — the day of a negative moment was truncated rather than floored.

  • The date-time clause of Astro.date_time_new_moon_before/1 was defined as Astro.date_time_new_moon_at_or_before/1, which carried its documentation. It is now a clause of date_time_new_moon_before/1, and date_time_new_moon_at_or_before/1 is deprecated.

  • Astro.lunar_phase_emoji/1 returns the new moon 🌑 for phases above 337.5°, where it returned the crescent moon 🌙, which is not a phase symbol.

  • Astro.Time.hours_and_date_to_date_time/2 declares the {:error, reason} it returns for an invalid date or a time of day of 24 hours or more.

  • Astro.Time.date_time_from_date_and_minutes/2 returns {:error, :invalid_date} for a date that is not valid in its calendar, where it raised MatchError, and converts a date in another calendar to its ISO date instead of reading its fields as ISO. Astro.solar_noon/2 returns the same errors and gives a date in another calendar the solar noon of that same day.

  • Astro.sun_azimuth_elevation/2, Astro.Time.local_sidereal_time/2 and Astro.Time.greenwich_mean_sidereal_time/1 raised ArgumentError for every input in an application with no time zone database configured. They now need none.

  • Astro.sunrise/3 and Astro.sunset/3 return {:error, :invalid_solar_elevation} for an unknown :solar_elevation, where they raised CaseClauseError, and their docs now list every error they return.

  • Astro.moonrise/3 and Astro.moonset/3 return {:error, :invalid_limb} or {:error, :invalid_interpolation} for an unknown :limb or :interpolation, where they raised CaseClauseError. Their docs and specs promised :moon_always_below_horizon and :moon_always_above_horizon where they return {:error, :no_time}, and now list every error they return.

  • Astro.new_visible_crescent/3 with the :odeh method, the default, or the :yallop method misclassified many crescents — a crescent 36 hours old at Mecca could be "not visible with optical aid" — because the lunar altitude and semi-diameter it uses were wrong (below). Classifications change on about half of evenings with :odeh and a quarter with :yallop, and the two methods now agree on 79% of evenings, where they agreed on 39%.

  • Astro.Lunar.lunar_altitude/2, angular_semi_diameter/1, equatorial_horizontal_parallax/1, horizontal_dip/1, topocentric_lunar_parallax/2 and topocentric_lunar_altitude/2 returned wrong values, because the arcsine they share treated its ratio argument as degrees. lunar_altitude/2 now agrees with the JPL ephemeris to within 0.006°.

  • Astro.Time.mean_sidereal_from_moment/1, and through it Astro.sun_azimuth_elevation/2, Astro.Time.greenwich_mean_sidereal_time/1, local_sidereal_time/2 and Astro.Lunar.lunar_altitude/2, measured sidereal time from Terrestrial rather than Universal Time, about 0.27° ahead. They now match Meeus's worked examples, and the sun's elevation agrees with the JPL ephemeris to within 0.01°.

  • Astro.Time.apparent_sidereal_from_moment/1 applied the formula for 0h UT at every time of day. It now returns the apparent sidereal time, as Astro.Coordinates.gast/1 does.

  • Astro.new_visible_crescent/3 with the :schaefer method modelled the sky as dark while the Sun was less than 1° below the horizon, so it could report a crescent under an hour old as visible to the naked eye. Twilight now brightens the sky from the horizon down.

  • Astro.Lunar.lunar_node/1 returned the node's distance from the equinoctial point about 9,000 years after the given moment. The doc of Astro.Lunar.moon_node/1 now says it returns the Moon's argument of latitude, which it always has.

Astro version 2.6.1

This is the changelog for Astro version 2.6.1, released on September 24th, 2026. For older changelogs please consult the release tag on GitHub

Enhancements

  • The periodic-term series behind lunar phases, new moons, Astro.moon_position_at/1 and crescent visibility are zipped into tuples at compile time and summed in a single pass, roughly halving their cost. Results are unchanged, bit for bit.

  • Sunrise, sunset, moonrise, moonset and crescent visibility are 1.6 to 1.75 times faster: the ephemeris is decoded in one pass per axis and evaluated without per-coefficient closures or list reversals, and its segments are indexed when it loads. Results are unchanged, bit for bit.

  • Rise and set functions resolve the location's time zone once per call rather than once per candidate event, which had doubled the lookup for many locations, and Astro.hours_of_daylight/2 and Astro.duration_of_daylight/2 reuse sunrise's zone for sunset. A time zone lookup can cost more than the astronomy itself, so calls using the default :time_zone gain the most.

Astro version 2.6.0

This is the changelog for Astro version 2.6.0, released on September 22nd, 2026. For older changelogs please consult the release tag on GitHub

Breaking Changes

  • The minimum supported Elixir version is now 1.17, raised from 1.11. Astro.duration_of_daylight/2 is therefore always defined, rather than only on releases where Duration is available.

Enhancements

  • Supports tz_world: "~> 2.4" only to allow use of the TzWorld.Backend.SpatialIndex backend.

  • Added guides for getting started, solar events and lunar events. Their examples are doctested, so they cannot drift from the library.

Bug Fixes

  • Astro.hours_of_daylight/2 and Astro.duration_of_daylight/2 now return the same result on every Elixir release. They derived the day length from DateTime.diff/2 at second precision, whose treatment of the microsecond components changed in Elixir 1.19, so one location and date returned 14:18:45 on Elixir 1.18 and earlier but 14:18:44 from 1.19 onwards.

  • Time zone resolution returns {:error, :tz_world_data_not_installed} when tz_world is a dependency but its time zone data has never been downloaded, instead of leaking the bare POSIX {:error, :enoent}. Running mix tz_world.update installs the data.

Astro version 2.5.0

This is the changelog for Astro version 2.5.0, released on August 9th, 2026. For older changelogs please consult the release tag on GitHub

Enhancements

  • A compact ephemeris covering 1900 to 2100 now ships with the package, so Astro works immediately after installation with no download step. It is extracted from JPL's DE440s kernel and yields identical results; mix astro.download_ephemeris remains available for the full 1849 to 2150 range and takes precedence when present.

  • mix astro.build_ephemeris builds a compact ephemeris from a JPL DE-series kernel, keeping only the Sun, Moon and Earth segments over a chosen span of years at roughly 42 KB per year. Options include --from, --to, --source and --keep-earth.

Bug Fixes

  • Ephemeris downloads now pin TLS 1.2. Erlang offers TLS 1.3 by default on OTP 26 and later, but NASA NAIF's server fails that handshake, which surfaced as {:failed_connect, ..., :closed} while curl appeared to work; this fix was described in the 2.2.2 release notes but the code change was not included until now. Thanks to @allenwyma for the report. Closes #10.

Astro version 2.4.0

This is the changelog for Astro version 2.4.0 released on July 15th, 2026. For older changelogs please consult the release tag on GitHub

Enhancements

  • Prefer Tz.TimeZoneDatabase over Tzdata.TimeZoneDatabase in the compile-time default when both libraries are loaded, remove the tzdata dependency entirely, and use tz for astro's own development and test environments. Astro remains time zone database agnostic: the :elixir :time_zone_database runtime configuration takes precedence, any Calendar.TimeZoneDatabase implementation works, and neither database is forced on consumers.

Astro version 2.3.3

This is the changelog for Astro version 2.3.3 released on July 5th, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Astro.moonrise/3 and Astro.moonset/3 now return {:error, :not_found} for a date outside the ephemeris range instead of raising a MatchError, completing the treatment applied to the sun events in 2.3.2. The moon-event scan confirms its search span — padded by one Lagrange interpolation interval — is covered by the ephemeris before computing altitudes.

  • Astro.equinox/2 and Astro.solstice/2 now return {:error, :year_out_of_range} for years outside 1000 CE to 3000 CE (the documented accuracy domain) instead of raising a FunctionClauseError. A far-past or far-future date reached through an astronomical calendar such as Persian now fails cleanly.

  • Astro.new_visible_crescent/3,4 now return {:error, :not_found} when the date is outside the ephemeris range, distinct from {:error, :no_sunset} which is reserved for a genuine polar no-sunset day. Callers can now tell missing data apart from a real astronomical condition.

Astro version 2.3.2

This is the changelog for Astro version 2.3.2 released on July 4th, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Astro.sunrise/3 and Astro.sunset/3 now return {:error, :not_found} for a date outside the ephemeris range instead of raising a MatchError. The sun-event scan confirms its search window is covered by the ephemeris before computing altitudes, so a far-future or far-past date — such as one reached through an astronomical calendar like Persian — fails cleanly.

Astro version 2.3.1

This is the changelog for Astro version 2.3.1 released on June 30th, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Fix compilation failure in downstream libraries (such as Calendrical) that compute ancient dates while a non-UTC time zone database like Tzdata.TimeZoneDatabase is configured. Astro.Time.date_time_from_date_and_minutes/2 performed UTC-only arithmetic via the configured time zone database, which can return :time_zone_not_found for dates outside its range; it now uses Calendar.UTCOnlyTimeZoneDatabase for that arithmetic. Thanks to @probably-not for the report.

Astro version 2.3.0

This is the changelog for Astro version 2.3.0 released on June 19th, 2026. For older changelogs please consult the release tag on GitHub

Enhancements

  • Add duration_of_daylight/2, returning the duration of daylight for a location and date as a Duration.t/0. Unlike hours_of_daylight/2 (which returns a Time.t/0 capped at ~T[23:59:59]), it represents a full 24 hours of daylight in the polar summer as %Duration{hour: 24}. It is defined only on Elixir 1.17 and later, where the Duration module is available.

Astro version 2.2.3

This is the changelog for Astro version 2.2.3 released on June 15th, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Fix hours_of_daylight/2 for sub-polar latitudes near the solstice. Thanks to @andykent for the issue. Closes #11.

Astro version 2.2.2

This is the changelog for Astro version 2.2.2 released on June 9th, 2026. For older changelogs please consult the release tag on GitHub

Addendum

  • The fix for #10 did not land in this release. It landed in 2.5.0 on August 9th, 2026.

Bug Fixes

  • Fix ephemeris download failing with :failed_connect/:closed on OTP 26+, where Erlang offers TLS 1.3 by default but NASA NAIF's server has a broken TLS 1.3 handshake. Both mix astro.download_ephemeris and the runtime auto-downloader now pin to TLS 1.2 (the version curl already negotiates). Thanks to @allenwyma for the report. Closes #10.

Astro version 2.2.1

This is the changelog for Astro version 2.2.1 released on May 23rd, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Fix date_time_from_julian_days to always return proleptic-Gregorian dates.

Astro version 2.2.0

This is the changelog for Astro version 2.2.0 released on May 21st, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Recover from unwriteable ephemeric download directory by attempting to write to /temp/astro

Enhancements

  • Improve logging for the ephemeric downloading events to aid debugging.

Astro version 2.1.1

This is the changelog for Astro version 2.1.1 released on April 25th, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Properly ensure tz_world is actually optional.

Astro version 2.1.0

This is the changelog for Astro version 2.1.0 released on April 7th, 2026. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Fix application startup when neither :tz nor :tzdata is configured. Astro.default_options/0 now falls back to time_zone_database: nil instead of raising CondClauseError. Calls that do not require a time zone database (e.g. time_zone: :utc) now work without any time zone library installed.

  • Fix Astro.Supervisor.start_link/2 to gracefully handle the case where :tz_world is not installed. Previously the supervisor unconditionally referenced TzWorld.Backend.DetsWithIndexCache and crashed at startup when the optional dependency was missing.

Enhancements

  • Add Astro.new_visible_crescent/3 to predict the visibility of the new crescent moon at a given location on a given date. Three published criteria are supported via the method argument:

    • :odeh (default) — Odeh (2006) empirical criterion based on 737 observations using topocentric ARCV and a Danjon limit of 6.4°.

    • :yallop — Yallop (1997) empirical criterion based on 295 observations using geocentric ARCV.

    • :schaefer — Schaefer (1988/2000) physics-based model computing the contrast between crescent brightness and twilight sky brightness against the human contrast detection threshold.

  • Add Astro.new_visible_crescent/4 accepting atmospheric options for the Schaefer method (:extinction parameter).

  • Add Astro.Ephemeris.Downloader which automatically downloads the JPL DE440s ephemeris file (~32 MB) from NASA NAIF on first application start and caches it under the user cache directory. The download URL and cache path can be overridden with the :ephemeris_url and :ephemeris application environment keys. If the download fails, Astro.Application.start/2 now returns a clear error message explaining how to install the file manually.

Astro version 2.0.0

This is the changelog for Astro version 2.0.0 released on March 14th, 2026. For older changelogs please consult the release tag on GitHub

Breaking changes

  • Rename Astro.Solar.solar_longitude/1 to Astro.Solar.solar_ecliptic_longitude/1 and Astro.Lunar.lunar_longitude/1 to Astro.Lunar.lunar_ecliptic_longitude/1 to use unambiguous astronomical terminology.

  • Rename Astro.Lunar.new_moon/0 to Astro.Lunar.new_moon_phase/0, Astro.Lunar.full_moon/0 to Astro.Lunar.full_moon_phase/0, Astro.Lunar.first_quarter/0 to Astro.Lunar.first_quarter_phase/0, and Astro.Lunar.last_quarter/0 to Astro.Lunar.last_quarter_phase/0 to clarify that these return phase angle constants.

  • Rename Astro.Time.utc_datetime_from_terrestrial_datetime/1 to Astro.Time.utc_datetime_from_dynamical_datetime/1 to reflect the standard "dynamical time" terminology used in modern astronomical references.

  • Rename functions in Astro.Time that had names including "datetime" and consistently use the form "date_time".

  • Astro.Time.offset_for_zone/2 now returns {:ok, offset} or raises if there is an error resolving an offset. That can happen if the time zone is unknown, if there is no time in the zone or if the result is ambiguous due to DST shift.

  • Astro.obliquity/0 now returns its value in degrees (was previously radians). The only impact is to code that directly calls this function.

  • Astro.Earth.nutation/1 now returns a 3-tuple {nutation_in_longitude, nutation_in_obliquity, obliquity} instead of a single scalar value. The first element in the tuple has the same purpose as the return value of the original function. However its value may be slightly different due to the new underlying algorithms.

  • Astro.moon_position_at/1 now returns distance to the Moon in kilometres instead of metres.

  • Astro.sunrise/3 and Astro.sunset/3 now delegate to Astro.Solar.SunRiseSet which computes solar positions from the JPL DE440s numerical ephemeris rather than the previous NOAA/Meeus analytical polynomial series, and uses a scan-and-bisect solver rather than the previous iterative analytical formula.

  • Improved ΔT (delta-T) computation now uses variable ΔT based on IERS observations (1972–2025) and Meeus polynomial approximations for historical dates, replacing the previous fixed ΔT value. This improves the accuracy of all astronomical calculations but changes computed times for equinoxes, solstices, new moons, and lunar phases by up to ~22 seconds compared to version 1.x.

  • Sunrise/sunset and moonrise/moonset bisection tolerance tightened from 1.0 second to 0.01 seconds, yielding sub-second precision.

  • Remove Astro.Solar.sun_rise_or_set/3 and Astro.Solar.utc_sun_position/4 (the old NOAA/Meeus sunrise/sunset implementation). These functions were previously @doc false and are superseded by Astro.Solar.SunRiseSet.

Enhancements

Astro version 1.1.2

This is the changelog for Astro version 1.1.2 released on September 9th, 2025. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Fix Astro.sunrise/3 and Astro.sunset/3 when the resolved UTC datetime is ambiguous or has a gap (typically during a daylight savings transition). Thanks to @andykent for the PR. Closes #6 and #7.

Astro version 1.1.1

This is the changelog for Astro version 1.1.1 released on June 21st, 2024. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Remove :hackney and :tzdata from :extra_applications.

Astro version 1.1.0

This is the changelog for Astro version 1.1.0 released on June 18th, 2024. For older changelogs please consult the release tag on GitHub

Breaking Change

  • :tz_world is no longer a required dependency - it is now an optional dependency. This library is used to resolve a time zone name from a given latitude and longitude. When configured, it becomes the default method of resolving time zone names from a location. However it is no possible to provide alternative implementations for this resolution using the :time_zone_resolver option.

  • To retain the previous behaviour, applications should add {:tz_world, "~> 1.0"} to their dependencies.

Enhancements

  • Adds an option :time_zone_resolver to Astro.sunrise/3 and Astro.sunset/3 that is a 1-arity function that is invoked to resolve the time zone name from a given latitude and longitude. The default is to use TzWorld.timezone_at/1 if TzWorld is configured, otherwise an error is returned.

  • The default time zone database is now detected in the following order:

    1. Application.get_env(:elixir, :time_zone_database)

    2. TzData.TimeZoneDatabase if TzData is configured

    3. Tz.TimeZoneDatabase if Tz is configured

Astro version 1.0.2

This is the changelog for Astro version 1.0.2 released on May 27th, 2024. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Fix sunrise/sunset calculations when the solar elevation isn't 90 degrees. Thanks to @cloud8421 for the issue. Closes #5.

Astro version 1.0.1

This is the changelog for Astro version 1.0.1 released on April 6th, 2024. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Use only the configured time zone database to resolve time zone information. Therefore any module that implements the Calendar.TimeZoneDatabase behaviour can be used. This also makes the code align with the README so that either Tzdata or Tz can be configured as the systems time zone database (or any future library). Thanks to @ericlathrop for the issue. Closes #4.

Astro version 1.0.0

This is the changelog for Astro version 1.0.0 released on December 29th, 2022. For older changelogs please consult the release tag on GitHub

Enhancements

  • Release 1.0. This library was started four years ago and the public API has been stable for at least three of those years.

  • Adds Astro.sun_azimuth_altitude/2. Thanks to @kimlai for the suggestion. Closes #3.

Astro version 0.10.0

This is the changelog for Astro version 0.10.0 released on November 7th, 2022. For older changelogs please consult the release tag on GitHub

Enhancements

  • Adds Astro.Math.floor/1 and Astro.Math.ceil/1 which are needed to support Tempo.

Astro version 0.9.2

This is the changelog for Astro version 0.9.2 released on September 1st, 2022. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Update :tz_world to "~> 1.0" which will also remove Elixir 1.14 warnings

Astro version 0.9.1

This is the changelog for Astro version 0.9.1 released on October 23rd, 2021. For older changelogs please consult the release tag on GitHub

Bug Fixes

  • Ensure that gregorian_seconds is an integer before passing it to Tzdata.periods_for_time/3. Thanks to @dvic for the report. Fixes #2.

Astro version 0.9.0

This is the changelog for Astro version 0.9.0 released on October 8th, 2021. For older changelogs please consult the release tag on GitHub

Please note that Elixir 1.11 or later is required.

Enhancements

  • Adds Astro.lunar_phase_emoji/1 to produce a single grapheme string representing the image of the moon phase for a given lunar angle.

Astro version 0.8.0

This is the changelog for Astro version 0.8.0 released on October 3rd, 2021. For older changelogs please consult the release tag on GitHub

Please note that Elixir 1.11 or later is required.

Enhancements

  • Convert some identity functions to macros which improves runtime performance

  • Add additional specs and docs to Astro.Math module

Astro version 0.7.0

This is the changelog for Astro version 0.7.0 released on September 10th, 2021. For older changelogs please consult the release tag on GitHub

Please note that Elixir 1.11 or later is required.

Bug Fixes

  • Revert Astro back to a pure library application. The supervisor for TzWorld still needs to be started. This fix brings the code back into line with the README. Thanks to @dvic for the report. Closes #1.

Astro version 0.6.0

This is the changelog for Astro version 0.6.0 released on September 5th, 2021. For older changelogs please consult the release tag on GitHub

Please note that Elixir 1.11 or later is required.

Bug Fixes

  • Fix Astro.Math.atan_r/2

  • Fix ephemeris calculation

Breaking changes

  • Change Time.date_time_{from, to}_iso_days/1 to Time.date_time_{from, to}_moment/1

Enhancements

Astro version 0.5.0

This is the changelog for Astro version 0.5.0 released on August 26th, 2021. For older changelogs please consult the release tag on GitHub

Please note that Elixir 1.11 or later is required.

Bug Fixes

  • Updates documentation to be clear about installation and setup requirements for tz_world

  • Fixes test data for São Paulo now that it no longer uses DST

  • Ensure :astro is started in test mode

Enhancements

This primary focus of this release is to add lunar calculations for moon phase.

Astro version 0.4.0

This is the changelog for Astro version 0.4.0 released on February 16th, 2020. For older changelogs please consult the release tag on GitHub

Breaking Change

  • When no timezone is found the return is changed from {:error, :timezone_not_found} to {:error, :time_zone_not_found} to be consistent with Elixir and TzData.

Astro version 0.3.0

This is the changelog for Astro version 0.3.0 released on December 9th, 2019. For older changelogs please consult the release tag on GitHub

Change in behaviour

  • Seconds are no longer truncated to zero when calculating datetimes and durations

Enhancements

  • Add Astro.solar_noon/2 to return the true solar noon for a location and date

  • Add Astro.hours_of_daylight/2 to return hours, minutes and seconds as a Time.t() representing the number of daylight hours for a give location and date

  • Add Astro.sun_apparent_longitude/1 to return the apparent solar longitude on a given date. The result, a number of degrees between 0 and 360, can be used to determine the seasons.

Astro version 0.2.0

This is the changelog for Astro version 0.2.0 released on December 6th, 2019. For older changelogs please consult the release tag on GitHub

Enhancements

  • Add Astro.equinox/2and Astro.solstice/2 to calculate solstices and equinoxes for a year. From these can be derived the seasons.

  • Add Astro.Time.datetime_from_julian_days/1

  • Add Astro.Time.utc_datetime_from_terrestrial_datetime/1

Astro version 0.1.0

This is the changelog for Astro version 0.1.0 released on December 5th, 2019. For older changelogs please consult the release tag on GitHub

Enhancements