GreenCal.Astro.Time (GreenCal v0.2.0)

Copy Markdown View Source

Time scales, Julian day, ΔT, sidereal time, nutation and obliquity.

The two time scales, and why they matter

Two time scales coexist in this kind of computation, and mixing them up is the classic mistake:

  • UT (universal time, ≈ UTC) — Earth's rotation. It drives sidereal time, hence hour angles, hence rise/set times.
  • TT (terrestrial time) — a uniform scale. It is what the ephemeris series (Sun and Moon positions) consume.

TT = UT + ΔT

ΔT is ≈ 69 s in 2026 and slowly grows. Applying ΔT on both sides (or on neither) introduces a systematic bias: ~69 s on rise times, and ~38″ on the lunar longitude (the Moon moves 0.55″ per second).

Naming convention throughout the library:

  • jd — Julian day in UT
  • jde — Julian day in TT (Meeus' "Julian Ephemeris Day")

ΔT

Three regimes:

  • Before 2000 — Espenak & Meeus polynomials (NASA GSFC, Five Millennium Canon of Solar Eclipses), which were fit to the historical observations.
  • 2000 to early 2026 — observed IERS values (USNO ser7/deltat.data, retrieved 2026-07-28), linearly interpolated between the January anchors. The Espenak & Meeus 2005–2050 branch is not used there: Earth's rotation sped up after 2005 and the polynomial overshoots by ~6 s in 2026 (75.1 s predicted vs 69.11 s observed).
  • After the table — the last observed value is held flat until 2050, then bridged linearly to the long-term parabola at 2150. Future ΔT is genuinely unknowable (that is the whole reason IERS exists); holding ~69 s is a far better guess for the coming decades than the polynomial's 75–93 s. Expect the error to stay < 1 s for ~10 years and grow slowly after.

For use cases that demand better, delta_t can be overridden everywhere through the :delta_t option (in seconds).

Summary

Functions

Cosine of an angle in degrees.

Decimal year of a Julian day, the variable of the ΔT polynomials.

Degrees per radian.

ΔT = TT − UT, in seconds, for a Julian day.

Ecliptic (λ, β) → equatorial (α, δ), in degrees (Meeus 13.3/13.4).

Greenwich apparent sidereal time, in degrees: GMST + Δψ·cos ε.

Greenwich mean sidereal time, in degrees, for a UT Julian day (Meeus 12.4).

The J2000.0 epoch as a Julian day.

Converts a UT Julian day to a Julian Ephemeris Day (TT).

Julian centuries elapsed since J2000.0.

Julian day (UT) of a date at 0h, of a DateTime or of a NaiveDateTime.

Julian day from year / month / decimal day (Gregorian calendar).

Mean obliquity of the ecliptic ε₀, in degrees (Meeus 22.2).

Normalizes an angle into [-180, 180).

Normalizes an angle into [0, 360).

Nutation in longitude and in obliquity, in degrees (Meeus ch. 22, short series).

Radians per degree.

Sine of an angle in degrees.

UTC DateTime corresponding to a UT Julian day.

True obliquity ε = ε₀ + Δε, in degrees.

Functions

cos_d(x)

Cosine of an angle in degrees.

decimal_year(jd)

@spec decimal_year(float()) :: float()

Decimal year of a Julian day, the variable of the ΔT polynomials.

Computed arithmetically as Julian years since 2000-01-01 — valid for any date, arbitrarily far in past or future. The ≤ 0.002-year drift against the calendar year is far below ΔT's own uncertainty.

deg()

Degrees per radian.

delta_t(jd)

@spec delta_t(float()) :: float()

ΔT = TT − UT, in seconds, for a Julian day.

Observed IERS values on 2000–2026, Espenak & Meeus polynomials before, a documented extrapolation after. See the @moduledoc.

ecliptic_to_equatorial(lambda, beta, eps)

@spec ecliptic_to_equatorial(float(), float(), float()) :: {float(), float()}

Ecliptic (λ, β) → equatorial (α, δ), in degrees (Meeus 13.3/13.4).

gast(jd)

@spec gast(float()) :: float()

Greenwich apparent sidereal time, in degrees: GMST + Δψ·cos ε.

Strictly speaking the t argument (Julian century) should be in TT; using UT instead shifts the result by about 10⁻⁷ degree.

gmst(jd)

@spec gmst(float()) :: float()

Greenwich mean sidereal time, in degrees, for a UT Julian day (Meeus 12.4).

j2000()

The J2000.0 epoch as a Julian day.

jd_to_jde(jd, delta_t \\ nil)

@spec jd_to_jde(float(), number() | nil) :: float()

Converts a UT Julian day to a Julian Ephemeris Day (TT).

delta_t may be forced (seconds) — required to reproduce Meeus' published examples, which are given directly in TT.

julian_century(jd)

@spec julian_century(float()) :: float()

Julian centuries elapsed since J2000.0.

julian_day(dt)

@spec julian_day(Date.t() | DateTime.t() | NaiveDateTime.t()) :: float()

Julian day (UT) of a date at 0h, of a DateTime or of a NaiveDateTime.

A DateTime in a non-UTC zone is converted to UTC through its offset: no time zone database is required.

iex> GreenCal.Astro.Time.julian_day(~U[2000-01-01 12:00:00Z])
2451545.0

iex> GreenCal.Astro.Time.julian_day(~D[2000-01-01])
2451544.5

julian_day(year, month, day)

@spec julian_day(integer(), integer(), number()) :: float()

Julian day from year / month / decimal day (Gregorian calendar).

Meeus, Astronomical Algorithms, formula 7.1. Gregorian only: before 1582-10-15 the result is a proleptic extrapolation.

iex> GreenCal.Astro.Time.julian_day(1957, 10, 4.81)
2436116.31

mean_obliquity(t)

@spec mean_obliquity(float()) :: float()

Mean obliquity of the ecliptic ε₀, in degrees (Meeus 22.2).

norm180(x)

@spec norm180(float()) :: float()

Normalizes an angle into [-180, 180).

norm360(x)

@spec norm360(float()) :: float()

Normalizes an angle into [0, 360).

nutation(t)

@spec nutation(float()) :: {float(), float()}

Nutation in longitude and in obliquity, in degrees (Meeus ch. 22, short series).

Accuracy ≈ 0.5″, more than enough here.

Returns {delta_psi, delta_eps}.

rad()

Radians per degree.

sin_d(x)

Sine of an angle in degrees.

to_datetime(jd, precision \\ :second)

@spec to_datetime(float(), :second | :microsecond) :: DateTime.t()

UTC DateTime corresponding to a UT Julian day.

Rounded to the second by default; pass :microsecond for full precision.

true_obliquity(t)

@spec true_obliquity(float()) :: float()

True obliquity ε = ε₀ + Δε, in degrees.