Astro

Hex.pmHex.pmHex.pmHex.pm

Astro is a library to provide accurate astronomical functions with a focus on functions that support solar, lunar and lunisolar calendars such as the Islamic, Chinese, Hebrew and Persian calendars.

Migration from Astro 1.x

The public API functions in the Astro module retain the same signatures in Astro 2.x which should mean a smooth migration in most cases.

When upgrading to Astro 2.x the following should be applied:

Usage

Installation and Configuration {: .Warning}

It's important to install and configure Astro correctly before use. See the installation notes below.

The primary functions are:

Solar functions

Lunar functions

Examples

# Sunrise in Sydney on December 4th
iex> Astro.sunrise({151.20666584, -33.8559799094}, ~D[2019-12-04])
{:ok, #DateTime<2019-12-04 05:37:08+11:00 AEDT Australia/Sydney>}
# Sunset in Sydney on December 4th
iex> Astro.sunset({151.20666584, -33.8559799094}, ~D[2019-12-04])
{:ok, #DateTime<2019-12-04 19:53:20+11:00 AEDT Australia/Sydney>}
# Sunset in the town of Alert in Nunavut, Canada
# ...doesn't exist since there is no sunset in summer
iex> Astro.sunset({-62.3481, 82.5018}, ~D[2019-07-01])
{:error, :no_time}
# ...or sunrise in winter
iex> Astro.sunrise({-62.3481, 82.5018}, ~D[2019-12-04])
{:error, :no_time}
# Hours of daylight on December 7th in Sydney
iex> Astro.hours_of_daylight {151.20666584, -33.8559799094}, ~D[2019-12-07]
{:ok, ~T[14:18:44]}
# No sunset in summer at high latitudes
iex> Astro.hours_of_daylight {-62.3481, 82.5018}, ~D[2019-06-07]
{:ok, ~T[23:59:59]}
# No sunrise in winter at high latitudes
iex> Astro.hours_of_daylight {-62.3481, 82.5018}, ~D[2019-12-07]
{:ok, ~T[00:00:00]}
# Calculate solstices for 2019
iex> Astro.solstice 2019, :december
{:ok, ~U[2019-12-22 04:19:19Z]}
iex> Astro.solstice 2019, :june
{:ok, ~U[2019-06-21 15:54:07Z]}
# Calculate equinoxes for 2019
iex> Astro.equinox 2019, :march
{:ok, ~U[2019-03-20 21:58:28Z]}
iex> Astro.equinox 2019, :september
{:ok, ~U[2019-09-23 07:49:52Z]}

Specifying a location

The desired location of sunrise or sunset can be specified as either:

Location units and direction

For this implementation, the latitude and longitude of the functions in Astro are specified as follows:

References

Installation

Add Astro as a dependency

Astro can be installed by adding astro to your list of dependencies in mix.exs:

def deps do
[
{:astro, "~> 2.0"}
]
end

The JPL Ephemeris

Astro computes rise and set times directly from a JPL Development Ephemeris. A compact ephemeris covering 1900 to 2100 is bundled with the package, so no download is required and Astro works as soon as it is installed.

The bundled file is extracted from JPL's DE440s kernel and contains only the Sun, Moon and Earth segments Astro uses. The Chebyshev coefficients are copied verbatim, so results are identical to those computed from the full JPL file for any date it covers.

Dates outside 1900–2100

For dates beyond the bundled range, download the full DE440s kernel, which covers 1849 to 2150:

mix astro.download_ephemeris

The file is placed in Astro's priv directory and takes precedence over the bundled ephemeris automatically. To place it elsewhere, pass --dest and configure the path:

config :astro,
ephemeris: "/path/to/de440s.bsp"

Dates outside the range of the loaded ephemeris return {:error, :not_found}.

Using a different ephemeris

The :ephemeris option accepts any compatible DAF/SPK kernel, such as de440.bsp or de441.bsp for a much wider date range.

To build your own compact ephemeris over a different span of years — trading file size for coverage at roughly 42 KB per year — use:

mix astro.build_ephemeris --from 2000 --to 2050

Coverage cannot exceed that of the source kernel, which is 1849 to 2150 for the default DE440s. Pass --source to subset a wider kernel such as de441.bsp.

Install a time zone database

A time zone database is required in order to support time zone conversions. Two popular options are tzdata and tz. The time zone database must be configured in config.exs or runtime.exs as the default time zone database. For example:

# If using tzdata
config :elixir,
:time_zone_database, Tzdata.TimeZoneDatabase
# If using tz
config :elixir,
:time_zone_database, Tz.TimeZoneDatabase

Optionally Install TzWorld

For functions such as Astro.sunrise/3 and Astro.sunset/3 it is common to expect the returned date time to be in the time zone of the specified location. The library tz_world provides that capability and, if configured, will automatically be used by those functions.

It is expected that tz_world is configured for most applications although it is not formally required.

tz_world does however require the download of nearly 30Mb of geojson data and a non-trivial post-processing step to format the data for efficient use by Astro. This might not be suitable for embedded devices and therefore Astro.sunrise/3, Astro.sunset/3, Astro.moonrise/3 and Astro.moonset/3 take an optional :time_zone_resolver option to support the implementation of a custom function to resolve the time zone name from a given location.

The following steps should be following if tz_world is configured.

Install TzWorld Data

Get all dependencies and then install the data required to resolve a time zone from a location which is used by the dependency tz_world.

mix deps.get
mix tz_world.update
# If testing locally also install for the test environment
MIX_ENV=test mix tz_world.update

Add TzWorld to supervision tree

It is also required that tz_world be added to your applications supervision tree by adding the relevant tz_world backend to it in your MyApp.Application module:

defmodule MyApp.Application do
use Application
def start(_type, _args) do
children = [
.....
# See the documentation for tz_world for the
# various available backends. This is the recommended
# backend.
TzWorld.Backend.DetsWithIndexCache
]
opts = [strategy: :one_for_one, name: Astro.Supervisor]
Supervisor.start_link(children, opts)
end
end

Configure your application module

Make sure that you have configured your application in mix.exs:

def application do
[
mod: {MyApp.Application, [strategy: :one_for_one]},
.....
]
end

Documentation can be found at https://hexdocs.pm/astro.

Developing Astro Locally

The Astro test suite requires a functioning tz_world database to be available in the test environment. Once all other dependencies are installed, execute:

MIX_ENV=test mix tz_world.update

Astro improved rise and set algorithms

The implementation of the sun and moon rise and set calculations in Astro 2.0 is a JPL DE440s ephemeris scan-and-bisect algorithm. Specifically:

For the Moon, it's additionally fully topocentric — the observer's geocentric displacement is applied to the Moon's position before computing altitude, rather than using the Meeus h0 = 0.7275π − 0.5667° parallax-in-altitude approximation.

There is a comparison document demonstrating how Astro's calculations for rise and set compare with Skyfield (JPL DE440s), USNO (DE430), and timeanddate.com.