Time scales - best practices
Handling time scales correctly may be complex, so this page shows ways to make it as simple as possible. See also Dates and time scales for more information.
All date arguments in CelestLab functions are relative to the TREF time scale. This may be a little disturbing as TREF is a time scale that only exists in CelestLab. Yet, the definition of TREF is simple. TREF (according to the default definition) is as uniform and continuous as TAI:
TREF = TAI + C (with C: constant)
The constant C is defined so that TREF is identical to UTC now ("now" meaning: at the time of CelestLab release). Doing this, the orientation of the Earth should be accurate enough when TREF is used in place of UT1 (for most applications, at least).
When necessary, other function arguments enable the user to specify how TREF relates to TT and UT1. These arguments are: ut1_tref (= UT1 - TREF) and tt_tref (= TT - TREF), and are defined by:
time/UT1 = time/TREF + ut1_tref
time/TT = time/TREF + tt_tref
where time/T
represents the time of some event in time scale T
. For instance, the time in time scale UT1 (time/UT1) is computed by adding the quantity ut1_tref (= UT1 - TREF) to the time in time scale TREF (time/TREF). Thus ut1_tref is function of time/TREF.
The quantities ut1_tref and tt_tref are expressed in seconds. For "date" quantities, using the notation "cjd": number of days since 1 Jan 1950 0h, we have by definition:
cjd/UT1 = cjd/TREF + ut1_tref / 86400
and cjd/TT = cjd/TREF + tt_tref / 86400
.
Thus, and to be very precise, ut1_tref and tt_tref are expressed in "TREF" seconds (seconds in TREF time scale, which is the same as "TAI" seconds, and also the same as "UTC" seconds).
Note that TT - TREF is constant (it does not depend on time) and that UT1 - TREF may not be constant. Also note that UT1 - TREF only matters if the orientation of the Earth has an influence on the results.
The functions for which the argument "ut1_tref" exists are: CL_dat_scaleConvert, CL_fr_convert, CL_fr_convertMat, CL_mod_siderealTime, CL_op_locTime, and also a few functions related to STELA and TLEs.
The functions for which the argument "tt_tref" exists are more numerous. But as we'll see in the examples, we generally don't have to care too much about this argument.
The 2 values "ut1_tref" and "tt_tref" enable the conversion to any other time scale, in particular TAI through the use of a constant that defines TT - TAI
, UTC through the use of global data that define TAI - UTC
(leap seconds), and of course UT1.
Here is a summary of recommended practices in order to minimize risks of errors - see examples for illustrations:
This example illustrates the most common use of time scales in CelestLab: no time scale explicitly referred to, all dates are relative to TREF.
That concerns cases where:
This second example is similar to example 1, except that the input / output dates are known or expected in some reference time scale that is not TREF.
That concerns cases where:
This third example is slightly more complex. It concerns cases where:
The only way to be sure not to make mistakes is to pass the correct value of ut1_tref to all functions that expect it. The value of the argument tt_tref is the default value.
Warning:
// ----------------------------------------------------- // Example 3 (based on example 2): // - Using default value for TT-TREF // - Convertion to TREF - computation in TREF // - UT1 matters // // This is an example of processing of IERS Bulletin B // that gives precise Earth Orientation Parameters (EOP) // Additional data and functions are used. See below. // ----------------------------------------------------- // ------------------------ // Process IERS data // Returns a structure that contains: // cjd/TREF, UT1-TREF(s) (1xN) // using data_iers (struct) that contains: // cjd/UTC, UT1-UTC(s), ... (1xN) // ------------------------ function [data]=process_EOP(data_iers) // Conversion: UTC => TREF cjd_tref = CL_dat_scaleConvert("UTC", "TREF", data_iers.cjd_utc); // Compute UT1 - TREF = (UT1 - UTC) + (UTC - TREF) // Note: UTC - TREF is a whole number of seconds // (=> rounded-off for more accuracy) utc_tref = round((data_iers.cjd_utc - cjd_tref) * 86400); ut1_tref = data_iers.ut1_utc + utc_tref; // sec // Check UT1-TREF is continuous (less than 0.1 sec variation / day) if (find(abs(diff(ut1_tref) ./ diff(cjd_tref)) > 0.1) <> []) error("ut1_tref is not continuous"); end data = struct("cjd_tref", cjd_tref, "ut1_tref", ut1_tref); endfunction // ------------------------ // Computes UT1-TREF from date in TREF // ------------------------ function [ut1_tref]=get_UT1(cjd_tref, data) // Interpolate (order 3) // Note: initial date subtracted => interpolation on durations ut1_tref = CL_interpLagrange(data.cjd_tref-data.cjd_tref(1), ... data.ut1_tref, cjd_tref-data.cjd_tref(1), n=4); endfunction // ------------------------ // MAIN // ------------------------ // Prepare data for the computation of ut1_tref // Load additional data and functions (in particular "load_EOP"). // data_iers: IERS data loaded from external files // => See directory "D" for more details D = CL_path("EOP", fullfile(CL_home(), "data")); exec(fullfile(D, "iers_util.sce")); data_iers = load_EOP(D); data = process_EOP(data_iers); // Date is relative to TDB cjd0_tdb = CL_dat_cal2cjd(2016, 12, 31, 0, 0, 0); cjd_tdb = cjd0_tdb + (0 : 0.5 : 2); // Computations done in TREF => convert to TREF first // Note: ut1_tref has no impact (argument not provided) cjd_tref = CL_dat_scaleConvert("TDB", "TREF", cjd_tdb); // All computations as in examples 1 and 2, except for the argument // "ut1_tref" that is explicitly passed to the functions (when needed) // Position of the Sun pos_sun = CL_eph_sun(cjd_tref) // Sidereal time ut1_tref = get_UT1(cjd_tref, data); tsid = CL_mod_siderealTime(cjd_tref, ut1_tref=ut1_tref) | ![]() | ![]() |
This last example is for users know what they do. Time arguments are given as necessary. All these advanced uses are dependent on not described features that may change in future versions, so be careful.
To be sure no "ut1_tref" or "tt_tref" argument has been forgotten in function calls, a simple way is to define %CL_UT1_TREF and/or %CL_TT_TREF and set them to %nan. As these values are used if no argument is given, the results will be impacted which will enable the error (missing argument) to be detected.
Notes: