# `Astro.Solar`
[🔗](https://github.com/kipcole9/astro/blob/v2.9.0/lib/astro/solar.ex#L1)

Solar position, orbital mechanics, and equinox/solstice calculations.

The Sun's apparent position is evaluated from the JPL DE440s
ephemeris via `Astro.Ephemeris`. The Meeus *Astronomical Algorithms*
series are retained only for the geometric mean longitude used by
the equation of time and for the initial estimate that seeds the
equinox and solstice search.

For sunrise and sunset calculations see `Astro.Solar.SunRiseSet`.

## Function groups

### Position

* `solar_position/1` — right ascension, declination and distance
* `solar_ecliptic_longitude/1` — apparent ecliptic longitude at a moment
* `solar_ecliptic_longitude_after/2`, `estimate_prior_solar_ecliptic_longitude/2`
* `sun_geometric_mean_longitude/1` — mean longitude from Julian centuries

### Time

* `equation_of_time/1` — difference between apparent and mean solar time
* `solar_noon_utc/2` — UTC solar noon for a given longitude

### Equinoxes and solstices

* `equinox_and_solstice/2` — March/September equinox or June/December solstice

### Solar elevation

* `solar_elevation/1` — zenith angle for geometric, civil, nautical,
  astronomical twilight or a custom elevation

## Time conventions

Functions in this module accept either a **moment** (fractional days
since epoch) or **Julian centuries** from J2000.0, as noted in each
function's documentation. Use `Astro.Time.julian_centuries_from_moment/1`
to convert between the two.

# `equation_of_time`

```elixir
@spec equation_of_time(float()) :: float()
```

Returns the equation of time in minutes.

### Arguments

* `julian_centuries` is any moment in time expressed
  as Julian centuries from J2000.0.

### Returns

* the discrepancy between apparent solar time and
  mean solar time in minutes as a `float`. A positive
  value means the sundial is ahead of the clock.

### Notes

The equation of time describes the discrepancy between
apparent solar time (which directly tracks the Sun's
diurnal motion) and mean solar time (which tracks a
theoretical mean Sun with uniform motion).

During a year the equation of time ranges from about
+16 min 33 s (around 3 November) to −14 min 6 s
(around 11 February), with zeros near 15 April,
13 June, 1 September, and 25 December.

The two principal causes are the obliquity of the
ecliptic (~23.44°) and the eccentricity of the
Earth's orbit (~0.0167).

### Examples

    iex> Astro.Solar.equation_of_time(0.0)
    -3.244441990189671

# `equinox_and_solstice`

```elixir
@spec equinox_and_solstice(pos_integer(), :march | :june | :september | :december) ::
  {:ok, DateTime.t()}
```

Returns the UTC datetime of an equinox or solstice.

### Arguments

* `year` is a positive integer Gregorian year.

* `event` is one of `:march`, `:june`, `:september`,
  or `:december` identifying the equinox or solstice.

### Returns

* `{:ok, datetime}` where `datetime` is a `DateTime.t()`
  in UTC.

### Notes

The `:march` and `:september` events are the equinoxes
(Sun's ecliptic longitude 0° and 180° respectively).
The `:june` and `:december` events are the solstices
(ecliptic longitude 90° and 270°).

### Examples

    iex> {:ok, dt} = Astro.Solar.equinox_and_solstice(2024, :march)
    iex> dt.year
    2024
    iex> dt.month
    3
    iex> dt.day
    20

# `estimate_prior_solar_ecliptic_longitude`

Returns an approximate moment at or before `t`
when the solar ecliptic longitude just exceeded `lambda` degrees.

### Arguments

* `lambda` is the target solar ecliptic longitude in degrees.

* `t` is any moment in time expressed as a moment
  (fractional days since the epoch).

### Returns

* the approximate moment (fractional days since the epoch)
  at or before `t` when the solar ecliptic longitude
  last exceeded `lambda` degrees.

### Examples

    # Estimate when the Sun last passed 90° before the June solstice
    iex> moment = Astro.Time.date_time_to_moment(~D[2024-06-21])
    iex> result = Astro.Solar.estimate_prior_solar_ecliptic_longitude(90, moment)
    iex> {:ok, dt} = Astro.Time.date_time_from_moment(result)
    iex> dt.year
    2024
    iex> dt.month
    6

# `solar_ecliptic_longitude`

Returns the solar ecliptic longitude in degrees.

### Arguments

* `t` is any moment in time expressed as a moment
  (fractional days since the epoch).

### Returns

* the solar ecliptic longitude in degrees as a `float`,
  in the range 0..360.

### Notes

The solar ecliptic longitude is the position of the Sun on the
celestial sphere along the ecliptic. It is also an effective
measure of the position of the Earth in its orbit around the Sun,
taken as 0° at the moment of the vernal equinox.

Since it is based on how far the Earth has moved in its orbit
since the equinox, it is a measure of what time of the tropical
year (the year of seasons) has elapsed, without the inaccuracies
of a calendar date which is perturbed by leap years and calendar
imperfections.

For a moment the loaded ephemeris does not cover, the longitude is
computed from the Meeus series, accurate to about 0.01°, as Astro 2.7
computed it for every moment. Calendars that count months by the
Sun's longitude, such as the Chinese and Japanese lunisolar
calendars, find their solar terms for dates of any era this way.

### Examples

    iex> moment = Astro.Time.date_time_to_moment(~D[2024-03-20])
    iex> Astro.Solar.solar_ecliptic_longitude(moment)
    359.87145169401623

    iex> moment = Astro.Time.date_time_to_moment(~D[1000-06-01])
    iex> Astro.Solar.solar_ecliptic_longitude(moment) |> Float.round(4)
    69.5887

# `solar_ecliptic_longitude_after`

```elixir
@spec solar_ecliptic_longitude_after(number(), Astro.Time.time()) :: Astro.Time.time()
```

Returns the moment (UT) of the first time at or after moment `t`
when the solar ecliptic longitude will be `lambda` degrees.

### Arguments

* `lambda` is the target solar ecliptic longitude in degrees.

* `t` is any moment in time expressed as a moment
  (fractional days since the epoch).

### Returns

* the moment (fractional days since the epoch) when
  the solar ecliptic longitude reaches `lambda` degrees.

### Examples

    # Find the June solstice (longitude 90°) in 2024
    iex> moment = Astro.Time.date_time_to_moment(~D[2024-05-22])
    iex> result = Astro.Solar.solar_ecliptic_longitude_after(90, moment)
    iex> {:ok, dt} = Astro.Time.date_time_from_moment(result)
    iex> dt.year
    2024
    iex> dt.month
    6

# `solar_noon_utc`

```elixir
@spec solar_noon_utc(float(), Astro.longitude()) :: float()
```

Returns solar noon as minutes since midnight UTC.

### Arguments

* `julian_centuries` is any moment in time expressed
  as Julian centuries from J2000.0.

* `longitude` is the longitude in degrees of the
  location from which solar noon is to be measured.
  West is negative.

### Returns

* solar noon as a `float` number of minutes since
  midnight UTC.

### Notes

Solar noon is the moment when the Sun passes a location's
meridian and reaches its highest position in the sky.
In most cases it does not occur at 12:00 local time.

### Examples

    iex> Astro.Solar.solar_noon_utc(0.0, 151.2093)
    1328.2818354717708

# `sun_geometric_mean_longitude`

```elixir
@spec sun_geometric_mean_longitude(float()) :: float()
```

Returns the Sun's geometric mean longitude in degrees.

### Arguments

* `julian_centuries` is any moment in time expressed
  as Julian centuries from J2000.0.

### Returns

* the mean solar longitude in degrees as a `float`,
  in the range 0..360.

### Notes

Mean longitude is a convenient uniform measure of how
far around its orbit a body has progressed since passing
the reference direction. While mean longitude assumes
constant speed, true longitude accounts for the body's
actual speed which varies around its elliptical orbit.
The difference between the two is the equation of the
centre.

### Examples

    iex> Astro.Solar.sun_geometric_mean_longitude(0.0)
    280.46646

---

*Consult [api-reference.md](api-reference.md) for complete listing*
