Astro.Time (Astro v2.1.0)

Copy Markdown View Source

Time scales, conversions, and calendar utilities for astronomical calculations.

Moments

A moment is the primary internal time representation used throughout Astro. It is a floating-point number of days since the Gregorian epoch (0000-01-01 00:00:00 UTC). The integer part identifies the calendar day; the fractional part represents the elapsed fraction of that day since midnight.

The public API in Astro accepts Date and DateTime parameters and converts them to moments before delegating to the implementation modules (Astro.Solar, Astro.Lunar, Astro.Solar.SunRiseSet, Astro.Lunar.MoonRiseSet). Those modules work primarily with moments and aim to never convert back to Date or DateTime internally for performance reasons.

Use date_time_to_moment/1 to convert a Date or DateTime to a moment, and date_time_from_moment/1 to convert a moment back to a UTC DateTime.

Time scales

Six time scales appear in astronomical calculations. Each serves a different purpose.

Universal Time (UTC)

The civil clock time standard. UTC is kept within one second of mean solar time at 0° longitude by the occasional insertion of leap seconds. It is the base time scale for moments: a moment is always in UTC.

See: universal_from_local/2, universal_from_standard/2, universal_from_dynamical/1.

Standard Time

UTC adjusted for a named time zone (e.g. "America/New_York"), including any daylight-saving offset. Standard time has discrete zone boundaries and changes at politically determined transition points.

See: standard_from_universal/2, universal_from_standard/2.

Local (Mean Solar) Time

UTC adjusted purely by geographic longitude — what a sundial reads. The offset is longitude / 360 of a day, a smooth function of position with no zone boundaries or daylight-saving rules.

See: local_from_universal/2, universal_from_local/2.

Dynamical Time

The uniform time scale used for computing planetary and lunar orbits. In Astro, "dynamical time" refers to TDB (Barycentric Dynamical Time) — the time argument expected by JPL ephemerides.

Two representations coexist:

Both representations derive ΔT from the unified delta_t/1 function.

Terrestrial Time (TT)

A uniform atomic time scale defined on Earth's geoid, the modern successor to Ephemeris Time (ET). TT is related to International Atomic Time (TAI) by a fixed offset: TT = TAI + 32.184 s. For solar-system calculations at Earth's distance, TT ≈ TDB to within ~1.7 ms, and Astro treats them as identical.

The DateTime conversion utc_date_time_from_dynamical_date_time/1 delegates to universal_from_dynamical/1 internally.

Sidereal Time

Measures Earth's rotation relative to the stars rather than the Sun. A sidereal day is ~3 minutes 56 seconds shorter than a solar day. Greenwich Mean Sidereal Time (GMST) is used to convert between equatorial coordinates and the local horizon; Greenwich Apparent Sidereal Time (GAST) adds the equation of the equinoxes (nutation in right ascension).

Functions: greenwich_mean_sidereal_time/1, local_sidereal_time/2, mean_sidereal_from_moment/1, apparent_sidereal_from_moment/1. See also Astro.Coordinates.gast/1.

Time scale conversion table

The table below shows how to convert from one time scale (row) to another (column). Each cell describes the conversion algorithm. A dash (—) marks the identity diagonal.

From \ ToUniversal (UTC)StandardLocalDynamicalTerrestrialSidereal
Universal (UTC)+ zone offset+ longitude/360+ ΔT+ ΔT (≈ dynamical)GMST polynomial in UTC
Standard− zone offset− zone + long/360− zone + ΔT− zone + ΔTvia UTC then GMST
Local− longitude/360− long/360 + zone− long/360 + ΔT− long/360 + ΔTvia UTC then GMST
Dynamical− ΔT− ΔT + zone− ΔT + long/360identity (≈)via UTC then GMST
Terrestrial− ΔT (≈ dyn)− ΔT + zone− ΔT + long/360identity (≈)via UTC then GMST
Siderealnot invertible†not invertible†not invertible†not invertible†not invertible†

Notes:

  • zone offset = UTC offset + DST offset for the named time zone, looked up via the configured TimeZoneDatabase.
  • longitude/360 = fraction of a day corresponding to the observer's geographic longitude (west negative).
  • ΔT = TT − UTC in seconds, converted to fractional days by dividing by 86400. Computed by delta_t/1.
  • Terrestrial ≈ Dynamical: TT and TDB differ by at most ~1.7 ms; Astro treats them as identical.
  • † Sidereal → other: sidereal time is not uniquely invertible because multiple UTC instants map to the same sidereal angle within a sidereal day. In practice, sidereal time is computed from UTC for a known date, not converted back.

ΔT

ΔT (TT − UTC) is the difference between the uniform dynamical time scale and civil clock time. It varies as Earth's rotation rate changes due to tidal friction and other geophysical effects. The unified delta_t/1 function returns ΔT in seconds for a given decimal year, drawing on IERS observations (1972–2025), the Meeus biennial table (1620–1971), and polynomial approximations for earlier and later dates.

Julian day system

The Julian day system provides a continuous day count independent of any calendar. It is the standard time-keeping framework in positional astronomy.

Julian Day (JD)

A continuous count of days (and fractions) from an epoch set at Greenwich noon on 1 January 4713 BC (Julian proleptic calendar). Day boundaries fall at noon, not midnight — JD 2451545.0 corresponds to 2000-01-01 12:00:00 TT.

Functions: julian_day_from_date/1, date_time_from_julian_days/1, date_from_julian_days/1.

J2000.0

The standard astronomical epoch: 2000 January 1.5 TT (Julian Day 2451545.0). Precession angles, nutation series, and ephemeris polynomials are all referenced to this epoch. Dynamical time in this library is expressed as seconds past J2000.0.

Constant: j2000/0 (returns the moment for J2000.0).

Modified Julian Day (MJD)

JD − 2400000.5. This shifts the day boundary from noon to midnight and produces smaller numbers, convenient for modern dates. MJD 0 corresponds to 1858-11-17 00:00:00 UTC.

Function: mjd/1.

Julian Centuries

A Julian century is exactly 36525 days (100 Julian years of 365.25 days each). Precession and nutation polynomials are evaluated in Julian centuries from J2000.0. Two conversion paths exist:

Summary

Types

A number of days as a float

A time of day as a float fraction of a day

A tuple of integer hours, integer minutes and integer seconds

A number of hours as a float

The float number of Julian centuries.

A float number of days since the Julian epoch.

A number of minutes as a float

A moment is a floating point representation of the fraction of a day.

Season expressed as a non-negative number that is <= 360 representing the sun angle of incidence (the angle at which the sun hits the earth).

A number of seconds as a float

A time is a floating point number of days since 0000-01-01 including the fractional part of a day.

A time zone name as a string

Functions

Returns the date for a given Julian day number.

Returns a UTC datetime by combining a date with a float number of minutes since midnight.

Returns a UTC datetime for a given Julian day number.

Returns a UTC DateTime for a given moment.

Returns a DateTime shifted to the requested time zone.

Returns a moment for a given date or datetime.

Returns ΔT (TT − UTC) in seconds for the given decimal year.

Returns the dynamical moment for a given universal (UTC) moment.

Returns dynamical time (TDB seconds past J2000.0) for a given UTC moment.

Returns a UTC moment for a given dynamical time (TDB seconds past J2000.0).

Returns the Greenwich Mean Sidereal Time (GMST) in degrees for a given datetime.

Returns a UTC datetime by combining a date with a float number of hours since midnight.

Returns the number of days for a given number of hours.

Returns an {hours, minutes, seconds} tuple for a given float number of hours since midnight.

Returns the J2000.0 epoch as a moment (Gregorian days since 0000-01-01).

Returns Julian centuries from J2000.0 for a given dynamical time.

Returns Julian centuries from J2000.0 for a given Julian day.

Returns Julian centuries from J2000.0 for a given UTC moment.

Returns the astronomical Julian day number for a given date.

Returns the Julian day for a given number of Julian centuries from J2000.0.

Returns the local mean solar time for a given universal (UTC) moment and location.

Returns the Local Mean Time offset in seconds for a given location and time zone.

Returns the local sidereal time in degrees for a given location and datetime.

Returns the Modified Julian Day (MJD) for a given date.

Returns the time zone offset as a fraction of a day for a given instant and time zone.

Returns the local mean solar time offset from UTC as a fraction of a day for a given longitude.

Returns an {hours, minutes, seconds} tuple for a given number of seconds since midnight.

Returns the standard time moment for a given universal (UTC) moment and time zone name or time zone offset.

Returns the universal (UTC) moment for a given dynamical moment.

Returns the universal (UTC) moment for a given local mean solar time moment and location.

Returns the universal (UTC) moment for a given standard time moment and time zone.

Returns a UTC datetime for a given dynamical time datetime.

Types

days()

@type days() :: number()

A number of days as a float

fraction_of_day()

@type fraction_of_day() :: number()

A time of day as a float fraction of a day

hms()

@type hms() :: {Calendar.hour(), Calendar.minute(), Calendar.second()}

A tuple of integer hours, integer minutes and integer seconds

hours()

@type hours() :: number()

A number of hours as a float

julian_centuries()

@type julian_centuries() :: number()

The float number of Julian centuries.

Since there are 365.25 days in a Julian year, a Julian century has 36,525 days.

julian_days()

@type julian_days() :: number()

A float number of days since the Julian epoch.

The current Julian epoch is defined to have been noon on January 1, 2000. This epoch is denoted J2000 and has the exact Julian day number 2,451,545.0.

minutes()

@type minutes() :: number()

A number of minutes as a float

moment()

@type moment() :: number()

A moment is a floating point representation of the fraction of a day.

season()

@type season() :: Astro.angle()

Season expressed as a non-negative number that is <= 360 representing the sun angle of incidence (the angle at which the sun hits the earth).

seconds()

@type seconds() :: number()

A number of seconds as a float

time()

@type time() :: number()

A time is a floating point number of days since 0000-01-01 including the fractional part of a day.

zone_name()

@type zone_name() :: binary()

A time zone name as a string

Functions

ajd(date)

See Astro.Time.julian_day_from_date/1.

apparent_sidereal_from_moment(t)

date_from_julian_days(julian_days)

Returns the date for a given Julian day number.

The Julian day is rounded to the nearest integer before conversion. This is suitable when only the calendar date is needed, without time-of-day information.

Arguments

  • julian_day is a Julian day number (float or integer).

Returns

Examples

iex> Astro.Time.date_from_julian_days(2458822.5)
{:ok, ~D[2019-12-05]}

date_time_from_date_and_minutes(minutes, date)

@spec date_time_from_date_and_minutes(minutes(), Calendar.date()) ::
  {:ok, Calendar.datetime()}

Returns a UTC datetime by combining a date with a float number of minutes since midnight.

Arguments

  • minutes is a float number of minutes since midnight.

  • date is any Calendar.date/0.

Returns

Examples

iex> Astro.Time.date_time_from_date_and_minutes(720.0, ~D[2024-06-21])
{:ok, ~U[2024-06-21 12:00:00Z]}

date_time_from_julian_days(julian_days)

@spec date_time_from_julian_days(julian_days()) :: {:ok, Calendar.datetime()}

Returns a UTC datetime for a given Julian day number.

Arguments

  • julian_day is a Julian day number as a float.

Returns

Examples

iex> Astro.Time.date_time_from_julian_days(2458822.5)
{:ok, ~U[2019-12-05 00:00:00Z]}

iex> Astro.Time.date_time_from_julian_days(2451545.0)
{:ok, ~U[2000-01-01 12:00:00Z]}

date_time_from_moment(t)

@spec date_time_from_moment(moment()) :: {:ok, DateTime.t()}

Returns a UTC DateTime for a given moment.

A moment is by definition in the UTC timezone, so the returned DateTime always has time_zone: "Etc/UTC". Microsecond precision is preserved.

Arguments

  • moment is a float representation of a UTC datetime where the integer part is the number of Gregorian days since 0000-01-01 and the fractional part is the fraction of a day since midnight.

Returns

  • {:ok, datetime} — a DateTime.t/0 in UTC with microsecond precision.

Examples

iex> Astro.Time.date_time_from_moment(740047.5)
{:ok, ~U[2026-03-07 12:00:00.000000Z]}

iex> Astro.Time.date_time_from_moment(740047.0)
{:ok, ~U[2026-03-07 00:00:00.000000Z]}

iex> Astro.Time.date_time_from_moment(740047.999999)
{:ok, ~U[2026-03-07 23:59:59.913599Z]}

date_time_in_requested_zone(utc_event_time, location, options)

Returns a DateTime shifted to the requested time zone.

Converts a UTC DateTime to the time zone specified in options. When the time zone is :utc, the datetime is returned unchanged. When :default, the time zone is resolved from the location using TzWorld (or a custom :time_zone_resolver). When a time zone name string is given, the datetime is shifted to that zone.

Arguments

  • utc_event_time is a UTC DateTime.

  • location is a Geo.PointZ struct with {longitude, latitude, altitude} coordinates. Used only when :time_zone is :default.

  • options is a map containing:

    • :time_zone:utc, :default, or a time zone name string.
    • :time_zone_database — the time zone database module (e.g. Tz.TimeZoneDatabase).
    • :time_zone_resolver — (optional) a 1-arity function (%Geo.Point{}) → {:ok, String.t()} for custom zone resolution.

Returns

  • {:ok, datetime} — the DateTime in the requested time zone.
  • {:error, reason} — if the time zone cannot be resolved or shifted.

Examples

iex> utc = ~U[2024-06-21 12:00:00Z]
iex> location = %Geo.PointZ{coordinates: {0.0, 51.5, 0.0}}
iex> options = %{time_zone: :utc, time_zone_database: Tz.TimeZoneDatabase}
iex> Astro.Time.date_time_in_requested_zone(utc, location, options)
{:ok, ~U[2024-06-21 12:00:00Z]}

date_time_to_moment(date_time)

@spec date_time_to_moment(Calendar.date() | Calendar.datetime()) :: moment()

Returns a moment for a given date or datetime.

A moment is a float where the integer part is the number of Gregorian days since 0000-01-01 and the fractional part is the fraction of a day since midnight. Moments are always in UTC.

When given a DateTime, it is first shifted to UTC before conversion. When given a Date, returns the integer Gregorian day number (midnight UTC).

Arguments

Returns

  • A moment as a float (or integer for Date inputs).

Examples

iex> Astro.Time.date_time_to_moment(~U[2026-03-07 12:00:00Z])
740047.5

iex> Astro.Time.date_time_to_moment(~D[2026-03-07])
740047

delta_t(year)

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

Returns ΔT (TT − UTC) in seconds for the given decimal year.

ΔT is the difference between Terrestrial Time (TT) and Universal Time (UTC). It varies over time as Earth's rotation rate changes.

Uses the best available data for each era:

  • 1972–2025: IERS-observed annual values with linear interpolation
  • 1620–1971: Meeus biennial lookup table with interpolation
  • Pre-1620 and post-2025: Polynomial approximations

Arguments

  • year is a decimal year (e.g., 2024.5 for mid-2024)

Returns

  • ΔT in seconds as a float.

Examples

iex> Astro.Time.delta_t(2000.0)
63.83

iex> Float.round(Astro.Time.delta_t(2024.5), 2)
69.24

dynamical_from_universal(t)

@spec dynamical_from_universal(time()) :: time()

Returns the dynamical moment for a given universal (UTC) moment.

Adds ΔT (converted to a fraction of a day) to the UTC moment, producing a dynamical moment suitable for evaluating Meeus-era polynomial series via julian_centuries_from_moment/1.

Arguments

  • t is a moment (float Gregorian days since 0000-01-01) in UTC.

Returns

  • A moment in the dynamical time scale (float Gregorian days).

Examples

iex> t = Astro.Time.date_time_to_moment(~U[2000-01-01 12:00:00Z])
iex> dt = Astro.Time.dynamical_from_universal(t)
iex> Float.round(dt - t, 6)
0.000739

dynamical_time_from_moment(moment)

@spec dynamical_time_from_moment(float()) :: float()

Returns dynamical time (TDB seconds past J2000.0) for a given UTC moment.

Applies a date-dependent ΔT via delta_t/1 to convert the UTC moment to TDB, the time scale expected by the JPL SPK ephemeris kernel.

Arguments

  • moment is a moment (float Gregorian days since 0000-01-01) in UTC.

Returns

  • Dynamical time as a float (TDB seconds past J2000.0).

Examples

iex> t = Astro.Time.date_time_to_moment(~U[2000-01-01 12:00:00Z])
iex> dt = Astro.Time.dynamical_time_from_moment(t)
iex> Float.round(dt, 1)
63.8

dynamical_time_to_moment(dynamical_time)

@spec dynamical_time_to_moment(float()) :: float()

Returns a UTC moment for a given dynamical time (TDB seconds past J2000.0).

This is the inverse of dynamical_time_from_moment/1. Subtracts a date-dependent ΔT to recover the UTC moment.

Arguments

  • dynamical_time is TDB seconds past J2000.0 (float).

Returns

  • A moment (float Gregorian days since 0000-01-01) in UTC.

Examples

iex> t = Astro.Time.date_time_to_moment(~U[2000-01-01 12:00:00Z])
iex> dt = Astro.Time.dynamical_time_from_moment(t)
iex> round_trip = Astro.Time.dynamical_time_to_moment(dt)
iex> Float.round(abs(round_trip - t) * 86400, 3)
0.0

greenwich_mean_sidereal_time(date_time)

(since 0.11.0)
@spec greenwich_mean_sidereal_time(Calendar.datetime()) :: moment()

Returns the Greenwich Mean Sidereal Time (GMST) in degrees for a given datetime.

GMST measures Earth's rotation relative to the stars. It is the hour angle of the mean vernal equinox at the Greenwich meridian.

Arguments

  • date_time is any Calendar.datetime/0. If not already in UTC, it is converted to UTC before computation.

Returns

  • GMST in degrees (float, typically 0–360).

Examples

iex> gmst = Astro.Time.greenwich_mean_sidereal_time(~U[2000-01-01 12:00:00Z])
iex> Float.round(gmst, 4)
280.7273

hours_and_date_to_date_time(time_of_day, map)

@spec hours_and_date_to_date_time(hours(), Calendar.date()) ::
  {:ok, Calendar.datetime()}

Returns a UTC datetime by combining a date with a float number of hours since midnight.

Arguments

  • time_of_day is a float number of hours since midnight (e.g. 13.5 for 1:30 PM).

  • date is any Calendar.date/0.

Returns

Examples

iex> {:ok, dt} = Astro.Time.hours_and_date_to_date_time(12.0, ~D[2024-06-21])
iex> DateTime.truncate(dt, :second)
~U[2024-06-21 12:00:00Z]

hours_to_days(hours)

@spec hours_to_days(hours()) :: days()

Returns the number of days for a given number of hours.

Arguments

  • hours is a number of hours.

Returns

  • The equivalent number of days as a float.

Examples

iex> Astro.Time.hours_to_days(48)
2.0

iex> Astro.Time.hours_to_days(6)
0.25

hours_to_hms(time_of_day)

@spec hours_to_hms(hours()) :: hms()

Returns an {hours, minutes, seconds} tuple for a given float number of hours since midnight.

Arguments

  • time_of_day is a float number of hours since midnight.

Returns

  • A {hour, minute, second} tuple. Fractional seconds are truncated.

Examples

iex> Astro.Time.hours_to_hms(0.0)
{0, 0, 0}

iex> Astro.Time.hours_to_hms(23.999)
{23, 59, 56}

iex> Astro.Time.hours_to_hms(15.456)
{15, 27, 21}

j2000()

Returns the J2000.0 epoch as a moment (Gregorian days since 0000-01-01).

J2000.0 is 2000 January 1.5 TT (noon on January 1, 2000). This is the standard reference epoch for precession, nutation, and ephemeris polynomials.

Returns

  • The J2000.0 moment as a float (730485.5).

Examples

iex> Astro.Time.j2000()
730485.5

julian_centuries_from_dynamical_time(dynamical_time)

@spec julian_centuries_from_dynamical_time(float()) :: float()

Returns Julian centuries from J2000.0 for a given dynamical time.

A pure arithmetic conversion: divides TDB seconds by the number of seconds in a Julian century (36525 × 86400).

Arguments

  • dynamical_time is TDB seconds past J2000.0 (float).

Returns

  • Julian centuries from J2000.0 as a float.

Examples

iex> Astro.Time.julian_centuries_from_dynamical_time(0.0)
0.0

iex> Astro.Time.julian_centuries_from_dynamical_time(36525.0 * 86400.0)
1.0

julian_centuries_from_julian_day(julian_day)

Returns Julian centuries from J2000.0 for a given Julian day.

Arguments

Returns

  • Julian centuries from J2000.0 as a float.

Examples

iex> Astro.Time.julian_centuries_from_julian_day(2451545.0)
0.0

iex> Float.round(Astro.Time.julian_centuries_from_julian_day(2451545.0 + 36525.0), 1)
1.0

julian_centuries_from_moment(t)

Returns Julian centuries from J2000.0 for a given UTC moment.

First converts the UTC moment to a dynamical moment (by adding ΔT), then computes Julian centuries from J2000.0. This is the time argument expected by Meeus-era polynomial series for precession, nutation, and orbital elements.

Arguments

  • t is a moment (float Gregorian days since 0000-01-01) in UTC.

Returns

  • Julian centuries from J2000.0 as a float.

Examples

iex> t = Astro.Time.date_time_to_moment(~U[2000-01-01 12:00:00Z])
iex> Float.round(Astro.Time.julian_centuries_from_moment(t), 6)
0.0

julian_day_from_date(date)

@spec julian_day_from_date(Calendar.date()) :: julian_days()

Returns the astronomical Julian day number for a given date.

Arguments

Returns

  • The Julian day as a float. The .5 fractional part reflects the Julian day convention of starting at noon.

Examples

iex> Astro.Time.julian_day_from_date(~D[2019-12-05])
2458822.5

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

julian_day_from_julian_centuries(julian_centuries)

@spec julian_day_from_julian_centuries(julian_centuries()) :: julian_days()

Returns the Julian day for a given number of Julian centuries from J2000.0.

This is the inverse of julian_centuries_from_julian_day/1.

Arguments

  • julian_centuries is a float number of Julian centuries from J2000.0.

Returns

  • The Julian day as a float.

Examples

iex> Astro.Time.julian_day_from_julian_centuries(0.0)
2451545.0

iex> Astro.Time.julian_day_from_julian_centuries(1.0)
2488070.0

local_from_universal(t, point_z)

@spec local_from_universal(time(), Geo.PointZ.t()) :: time()

Returns the local mean solar time for a given universal (UTC) moment and location.

Local mean solar time is UTC plus an offset derived purely from geographic longitude (longitude / 360 of a day). This is distinct from standard time, which uses named time zone boundaries and daylight-saving rules.

Arguments

  • t is a moment (float Gregorian days since 0000-01-01) in UTC.

  • location is a Geo.PointZ with {longitude, latitude, altitude}.

Returns

  • A moment in local mean solar time (float Gregorian days).

Examples

iex> location = %Geo.PointZ{coordinates: {-90.0, 40.0, 0.0}}
iex> t = 740047.5
iex> Astro.Time.local_from_universal(t, location)
740047.25

local_mean_time_offset(location, gregorian_seconds, time_zone)

Returns the Local Mean Time offset in seconds for a given location and time zone.

The offset is the difference between Local Mean Time at the given longitude and Standard Time in effect for the given time zone. Local Mean Time is the solar time at a specific longitude, while Standard Time is the civil time for the time zone.

Arguments

  • location is a Geo.PointZ struct with {longitude, latitude, altitude} coordinates.

  • gregorian_seconds is the number of seconds since the Gregorian epoch (0000-01-01 00:00:00).

  • time_zone is a time zone name string (e.g. "Etc/UTC").

Returns

  • A float representing the offset in seconds between Local Mean Time and Standard Time.

Examples

iex> location = %Geo.PointZ{coordinates: {0.0, 51.5, 0.0}}
iex> gregorian_seconds = 63_871_632_000
iex> Astro.Time.local_mean_time_offset(location, gregorian_seconds, "Etc/UTC")
0.0

local_sidereal_time(location, date_time)

(since 0.11.0)
@spec local_sidereal_time(Astro.location(), Calendar.datetime()) :: moment()

Returns the local sidereal time in degrees for a given location and datetime.

Local sidereal time is GMST plus the observer's geographic longitude.

Arguments

Returns

  • Local sidereal time in degrees (float).

Examples

iex> lst = Astro.Time.local_sidereal_time({0.0, 51.5}, ~U[2000-01-01 12:00:00Z])
iex> Float.round(lst, 4)
280.7273

mean_sidereal_from_moment(t)

mjd(date)

@spec mjd(Calendar.date()) :: julian_days()

Returns the Modified Julian Day (MJD) for a given date.

MJD is JD − 2400000.5, shifting the day boundary from noon to midnight and producing smaller numbers. MJD 0 corresponds to 1858-11-17 00:00:00 UTC.

Arguments

Returns

  • The Modified Julian Day as a float.

Examples

iex> Astro.Time.mjd(~D[2019-12-05])
58822.0

offset_for_zone(gregorian_seconds, time_zone, time_zone_database \\ Calendar.get_time_zone_database())

Returns the time zone offset as a fraction of a day for a given instant and time zone.

Arguments

  • gregorian_seconds is the number of seconds since the Gregorian epoch (0000-01-01 00:00:00).

  • time_zone is a time zone name string (e.g. "Europe/London").

  • time_zone_database is the time zone database module (defaults to Calendar.get_time_zone_database()).

Returns

  • The total offset (UTC offset + DST) as a fraction of a day (float).

  • :ambiguous_time if the instant falls in a DST overlap.

  • :no_such_time_or_zone if the zone is unknown or the instant falls in a DST gap.

Examples

iex> t = Date.to_gregorian_days(~D[2021-08-01]) * (60 * 60 * 24)
iex> Astro.Time.offset_for_zone(t, "Europe/London")
{:ok, 0.041666666666666664}

offset_from_longitude(longitude)

@spec offset_from_longitude(Geo.PointZ.t() | Astro.longitude()) :: moment()

Returns the local mean solar time offset from UTC as a fraction of a day for a given longitude.

The offset is longitude / 360 of a day. West longitudes (negative) produce negative offsets, east longitudes produce positive offsets.

Arguments

  • longitude is either a Geo.PointZ struct or a numeric longitude in degrees (west negative, east positive).

Returns

  • The offset as a fraction of a day (float). For example, −90° returns −0.25 (6 hours behind UTC).

Examples

iex> Astro.Time.offset_from_longitude(-90.0)
-0.25

iex> Astro.Time.offset_from_longitude(180.0)
0.5

seconds_to_hms(time_of_day)

@spec seconds_to_hms(fraction_of_day()) :: hms()

Returns an {hours, minutes, seconds} tuple for a given number of seconds since midnight.

Arguments

  • time_of_day is a number of seconds since midnight.

Returns

  • A {hour, minute, second} tuple. Fractional seconds are truncated.

Examples

iex> Astro.Time.seconds_to_hms(0.0)
{0, 0, 0}

iex> Astro.Time.seconds_to_hms(3214)
{0, 53, 34}

iex> Astro.Time.seconds_to_hms(10_000)
{2, 46, 39}

standard_from_universal(t, zone_name)

@spec standard_from_universal(time(), zone_name() | number()) :: time()

Returns the standard time moment for a given universal (UTC) moment and time zone name or time zone offset.

Standard time is UTC adjusted by the named time zone's UTC offset and any daylight-saving offset in effect at the given instant.

Arguments

  • t is a moment (float Gregorian days since 0000-01-01) in UTC.

  • zone_name is either a time zone name string (e.g. "America/New_York") or a numeric offset in fractional days.

Returns

  • A moment in standard time (float Gregorian days).

Examples

iex> t = Astro.Time.date_time_to_moment(~U[2024-01-15 12:00:00Z])
iex> Astro.Time.standard_from_universal(t, "Australia/Sydney")
739265.9200462963

iex> t = Astro.Time.date_time_to_moment(~U[2024-01-15 12:00:00Z])
iex> standard = Astro.Time.standard_from_universal(t, 0.25)
iex> standard - t
0.25

universal_from_dynamical(t)

@spec universal_from_dynamical(time()) :: time()

Returns the universal (UTC) moment for a given dynamical moment.

Subtracts ΔT (converted to a fraction of a day) from a dynamical moment, recovering the corresponding UTC moment.

Arguments

  • t is a moment (float Gregorian days since 0000-01-01) in dynamical time.

Returns

  • A moment in the UTC time scale (float Gregorian days).

Examples

iex> t = Astro.Time.date_time_to_moment(~U[2000-01-01 12:00:00Z])
iex> dyn = Astro.Time.dynamical_from_universal(t)
iex> Astro.Time.universal_from_dynamical(dyn)
730485.5

universal_from_local(t, point_z)

@spec universal_from_local(time(), Geo.PointZ.t()) :: time()

Returns the universal (UTC) moment for a given local mean solar time moment and location.

Subtracts the longitude-based offset (longitude / 360 of a day) from the local time to recover UTC. This is the inverse of local_from_universal/2.

Arguments

  • t is a moment (float Gregorian days since 0000-01-01) in local mean solar time.

  • location is a Geo.PointZ with {longitude, latitude, altitude}.

Returns

  • A moment in UTC (float Gregorian days).

Examples

iex> location = %Geo.PointZ{coordinates: {-90.0, 40.0, 0.0}}
iex> local_t = 740047.25
iex> Astro.Time.universal_from_local(local_t, location)
740047.5

universal_from_standard(t, zone_name)

@spec universal_from_standard(time(), zone_name() | number()) :: time()

Returns the universal (UTC) moment for a given standard time moment and time zone.

Subtracts the time zone offset (UTC offset + DST) from the standard time moment to recover UTC. This is the inverse of standard_from_universal/2.

Arguments

  • t is a moment (float Gregorian days since 0000-01-01) in standard time.

  • zone_name is either a time zone name string (e.g. "America/New_York") or a numeric offset in fractional days.

Returns

  • A moment in UTC (float Gregorian days).

Examples

iex> t = 740047.75
iex> utc = Astro.Time.universal_from_standard(t, 0.25)
iex> t - utc
0.25

utc_date_time_from_dynamical_date_time(datetime)

@spec utc_date_time_from_dynamical_date_time(Calendar.datetime()) ::
  {:ok, Calendar.datetime()}

Returns a UTC datetime for a given dynamical time datetime.

Converts a DateTime whose clock reading is in dynamical time (TDB ≈ TT) to the corresponding UTC DateTime by subtracting ΔT. Internally delegates to universal_from_dynamical/1.

Arguments

  • datetime is a DateTime whose clock reading is in dynamical time (TDB seconds, equivalently Terrestrial Time).

Returns

  • {:ok, utc_datetime} — the corresponding UTC DateTime.

Examples

iex> {:ok, dyn} = Astro.Time.date_time_from_julian_days(2451545.0)
iex> {:ok, utc} = Astro.Time.utc_date_time_from_dynamical_date_time(dyn)
iex> DateTime.truncate(utc, :second)
~U[2000-01-01 11:58:56Z]