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:
- The representation type (e.g. Gregorian or Julian calendar representation)
- The origin (e.g. J2000, JD, MJD, ...)
- 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 betweenTT
andTDB
, with a maximum error fo about 10 μs between 1600 and 2200. SeeTempo.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 fromTAI
.
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 - e2
Duration{Float64}(40, 0.0)
julia> value(Δe)
40.0
julia> e3 = Epoch(40, TAI)
2000-01-01T12:00:40.0000 TAI
julia> e1 - e3
ERROR: 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 += 50
2000-01-01T12:01:20.0000 TDB
julia> e1 -= 30.42
2000-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 > e2
false
julia> e1 == e2
true
Again, the operations are supported only if the two epochs belong to the same timescale.
Finally, it is also possible to construct ranges with Epoch
s, 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.