Epochs Handling and Conversions

In this tutorial, the general workflow to be followed when dealing with time representations and their transformations is presented. In particular, most of the features of this package are designed around the Epoch data type, which differently from the DateTime object, provides the capability to represent time in different standard and user-define time scales.

Creating Epochs

Time representions for space applications embed three different concepts:

  1. The representation type (e.g. Gregorian or Julian calendar representation)
  2. The origin (e.g. J2000, JD, MJD, ...)
  3. The time scale (e.g. TAI, TT, TDB, UTC, UT, ...)

All three infromation are considered when building an Epoch. In particular, within Tempo, the (interal) time representation is always based upon the Julian calendar, with the origin fixed at J2000, i.e., the 1st of January 2000 at noon. Different timescales are instead available, with the default one being the TDB. The set of pre-defined time scales supported by this package is:

  • TT: Terrestrial Time, is a time scale that is used for the prediction or recording of the positions of celestial bodies as measured by an observer on Earth.
  • TDB: Barycentric Dynamical Time is a relativistic time scale that is used for the prediction or recording of the positions of celestial bodies relative to the solar system's barycenter.
  • TAI: International Atomic Time is a time scale based on the average frequency of a set of atomic clocks.
  • TCG: Geocentric Coordinate Time is a relativistic coordinate time scale that is used for precise calculations of objects relative to the Earth.
  • TCB: Barycentric Coordinate Time is a relativistic coordinate time scale that is used for precise calculations of objects in the Solar System.
  • UTC: Coordinated Universal Time is the primary civil time standard which is kept within one second from the mean solar time (UT1). However, since the rotation of the Earth is irregular, leap seconds are periodically inserted to keep UTC within 0.9 seconds of UT1.
  • TDBH: Although TDBH is not an official time scale, it is here used to provide a more accurate transformation between TT and TDB, with a maximum error fo about 10 μs between 1600 and 2200. See Tempo.offset_tt2tdbh for more details.
  • GPS: GPS Time is a continuous time scale defined by the GPS Control segment defined as a constant offset of 19s from TAI.

ISO Strings

With this in mind, many different ways are available to create a new Epoch object. The first is based upon the ISO 8601 concept, an international standard to represent dates and times. The desired timescale can be either specified by appending its acronym to the string or as a second argument, as follows:

julia> e = Epoch("2022-01-02T06:30:00.0 TT")2022-01-02T06:29:59.9999 TT
julia> e = Epoch("2022-01-02T06:30:00.0")2022-01-02T06:29:59.9999 TDB
julia> e = Epoch("2022-01-02T06:30:00.0", TAI)2022-01-02T06:29:59.9999 TAI

As you can see, when we did not specify a timescale, TDB has been used by default. The usage of partial ISO strings is also supported:

julia> e = Epoch("2020-01-01")2020-01-01T00:00:00.0000 TDB
julia> e = Epoch("2021-01-30T01")2021-01-30T01:00:00.0000 TDB
julia> e = Epoch("2022-06-12 UTC")2022-06-12T00:00:00.0000 UTC

Julian Dates

Epoch objects can also be created from Julian Dates, Modified Julian Dates as well as Julian days or seconds since J2000. To parse a Julian Date, in days, the input string must be in the format JD DDDDDDDDD.ffffff:

julia> e = Epoch("JD 2451545.04")2000-01-01T12:57:36.0000 TDB
julia> e = Epoch("JD 2451545.04 TT")2000-01-01T12:57:36.0000 TT

Similarly, for Modified Julian Dates, the string format is MJD DDDDDDDDD.ffffff:

julia> e = Epoch("MJD 51544.54")2000-01-01T12:57:36.0000 TDB
julia> e = Epoch("MJD 51544.54 TT")2000-01-01T12:57:36.0000 TT

When a prefix is not specified, the epoch constructor assumes the input is expressed as Julian days since J2000:

julia> e = Epoch("9.0")2000-01-10T12:00:00.0000 TDB
julia> e = Epoch("9.0 TT")2000-01-10T12:00:00.0000 TT

As you can see, the timescale acronym can always be appended to the predefined string format to override the default time scale. Finally, it is also possible to create an epoch by specifing the number of seconds since J2000. In the latter case, the constructor has a slightly different form and always requires the timescale argument:

julia> e = Epoch(60.0, TT)2000-01-01T12:01:00.0000 TT
julia> e = Epoch(60.0, TerrestrialTime)2000-01-01T12:01:00.0000 TT
julia> e = Epoch{TerrestrialTime}(60.0)2000-01-01T12:01:00.0000 TT

DateTime

Finally, an Epoch can also be constructed from the DateTime object defined within this package:

julia> dt = DateTime(2001, 6, 15, 0, 0, 0, 0.0)2001-06-15T00:00:00.0000
julia> e = Epoch(dt, TT)2001-06-15T00:00:00.0000 TT
julia> e = Epoch(dt, TerrestrialTime)2001-06-15T00:00:00.0000 TT

Working with Epochs

Basic Operations

The Epoch type supports a limited subset of basic mathematical and logical operations on it. For example, the offset, in seconds, between two epochs can be computed by subtracting them:

julia> e1 = Epoch(90.0, TT)2000-01-01T12:01:30.0000 TT
julia> e2 = Epoch(50.0, TT)2000-01-01T12:00:50.0000 TT
julia> Δe = e1 - e2Duration{Float64}(40, 0.0)
julia> value(Δe)40.0
julia> e3 = Epoch(40, TAI)2000-01-01T12:00:40.0000 TAI
julia> e1 - e3ERROR: only epochs defined in the same timescale can be subtracted.

Notice that this operation can be performed only if the two epochs are defined on the same timescale. When computing the difference between two epochs, the result is returned in the form of a Duration object. The value can then be used to retrieve the actual number of seconds it represents.

Epochs can also be shifted forward and backwards in time by adding or subtracting an arbitrary number of seconds:

julia> e1 = Epoch(30.0, TDB)2000-01-01T12:00:30.0000 TDB
julia> e1 += 502000-01-01T12:01:20.0000 TDB
julia> e1 -= 30.422000-01-01T12:00:49.5800 TDB

You can check whether an epoch is greater than an other with the logical operators:

julia> e1 = Epoch(50.0, UTC)2000-01-01T12:00:50.0000 UTC
julia> e2 = Epoch(50.0, UTC)2000-01-01T12:00:50.0000 UTC
julia> e1 > e2false
julia> e1 == e2true

Again, the operations are supported only if the two epochs belong to the same timescale.

Finally, it is also possible to construct ranges with Epochs, with a default timestep of one Julian day. User-defined timesteps are assumed to be expressed in seconds.

julia> e1 = Epoch("2024-01-01T12:00:00")2024-01-01T12:00:00.0000 TDB
julia> e2 = Epoch("2024-01-05T12:00:00")2024-01-05T12:00:00.0000 TDB
julia> collect(e1:e2)5-element Vector{Epoch{BarycentricDynamicalTime, Float64}}: 2024-01-01T12:00:00.0000 TDB 2024-01-02T12:00:00.0000 TDB 2024-01-03T12:00:00.0000 TDB 2024-01-04T12:00:00.0000 TDB 2024-01-05T12:00:00.0000 TDB
julia> collect(e1:172800:e2)3-element Vector{Epoch{BarycentricDynamicalTime, Float64}}: 2024-01-01T12:00:00.0000 TDB 2024-01-03T12:00:00.0000 TDB 2024-01-05T12:00:00.0000 TDB

Julian Dates

A predefined set of functions is also provided to easily convert [Epoch] objects to Julian seconds, days and centuries since J2000:

julia> e = Epoch("2024-01-01T12:00:00 TAI")2024-01-01T12:00:00.0000 TAI
julia> j2000(e)8766.0
julia> j2000s(e)7.573824e8
julia> j2000c(e)0.24

Converting Between Time Scales

Epoch transformations between the standard and user-defined timescales are simply performed through the convert method by specifying the target time scale

julia> e = Epoch(90.0, TT)2000-01-01T12:01:30.0000 TT
julia> eTAI = convert(TAI, e)2000-01-01T12:00:57.8160 TAI
julia> eTCG = convert(TCG, e)2000-01-01T12:01:30.5058 TCG

These transformations are based on a directed graph of timescales (TIMESCALES) existing within Tempo. Set of functions provide then the offsets in seconds between each pair of connected timescales, offering a simple, effective and efficient way to compute these transformations.

julia> e = Epoch(90.0, TT)2000-01-01T12:01:30.0000 TT
julia> eTAI = convert(TAI, e)2000-01-01T12:00:57.8160 TAI

UTC and Leap Seconds

A special remark must be made on the conversion between TAI and UTC. The offset between these two timescales is defined by a leap seconds, which are introduced to keep the UTC time scale within 0.9 seconds from UT1. Since the rotation of the Earth is irregular, it is not possible to predict when a new leap second will be introduced in the future.

A leapsecond table is embedded within Tempo and will be manually updated each time a new leapsecond is introduced, so that the effort required from the user side is minimised. Indeed, transforming an Epoch from a generic timescale to UTC is a simple as:

julia> e = Epoch(90.0, TT)2000-01-01T12:01:30.0000 TT
julia> eUTC = convert(UTC, e)2000-01-01T12:00:25.8159 UTC

UTC to UT1

The offset between UT1 and UTC, which depends upon the rotation of the Earth, is available in the Earth Orientation Parameters (EOP) provided by the International Earth Rotation and Reference System Service (IERS). Since those parameters are also required to compute the orientation of the ITRF with respect to the ICRF, a decision has been made to define the UT1 timescale in FrameTransformations.jl, a different package which enhances Tempo with the capability to transform from and to UT1.