Skip to content

johanley/precision-timekeeping

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Precision Timekeeping

References for adding context:

  • The Explanatory Supplement to the Astronomical Almanac, various editions
  • SOFA and its Cookbook called SOFA Time Scale and Calendar Tools
  • Astrometry.jl

This project is implemented in Java. Similar implementations in other languages would need arbitrary precision arithmetic, which is widely implemented.

Quick view of example code that uses this library.

Time Precision in Various Domains

Precision Description
~0.000 002 ns World's best clocks
~0.001 ns ALMA telescope master clock
~1 ns CPU access L1 cache
~2 ns GPS satellite
~20 ns GPS receiver
~100 ns CPU access main memory
~130 ns 5G cell towers
~100,000 ns Network Time Protocol on a LAN

Design Choices In This Library

This library is not very large or complex. If you disagree with any of the design decisions mentioned below, changing the code isn't difficult.

Gregorian and Julian Calendars

The Gregorian calendar and the Julian calendar are implemented.

Proleptic Behaviour

Either calendar can be used for any date. There's no restriction to the historical facts of when a calendar was adopted in any jurisdiction.

Unrestricted Julian Dates

The Julian date is not restricted to dates having Julian date >= 0. This restriction is unfortunately found in many date-time libraries.

Arbitrary Precision

The date-time and Julian date can be defined to arbitrary precision for seconds and fractional days. This is implemented by using Java's BigDecimal class. This is an unusual property. Most date-time libraries don't allow arbitrary precision for the time of day. For example:

  • Java's java.time package stops at nanoseconds.
  • SOFA implements Julian dates with a pair of doubles. That library can represent a moment in time to an accuracy of ~20 microseconds.

Included Timescales

  • TAI is the core timescale. Other timescales are defined using an offset from TAI.
  • TT has a fixed offset from TAI.
  • TDB, whose offset from TAI is modeled as a simple periodic function.
  • GPS is modeled with a fixed offset from TAI.
  • UT1, whose offset from TAI comes from data files from IERS. That data starts 1962-01-01. You need to update that file manually. Has a back-door to let you define a fixed override value.
  • UTC, modeled as a fixed offset from TAI. Has a back-door to let you define a fixed override value.

Conversions Between Timescales At Sub-Millisecond Level

Time can be represented to arbitrary precision in this library. But conversions between timescales is another story:

  • some conversions are defined by convention, and can be taken to be "infinitely precise", so to speak
  • for the remaining conversions, the precision of the conversion varies

In this library, the goals are:

  • to ensure timescale conversions are always accurate to sub-millisecond level from 1980-01-01 to the present day, as a kind of minimal baseline
  • to execute timescale conversions in a single method call

The design of SOFA is different in this regard. In SOFA, specific conversions between timescales are implemented, each at the best possible precision. This is a good design for SOFA. But in SOFA, to go from one timescale to another, you need to think about the specific chain of conversions that gets you from A to B. In this library, it's always a single method call.

UT1-TAI Data From 1962-01-01 Onward

For converting UT1 to other timescales, the difference UT1-TAI in seconds is taken from a downloaded snapshot of the IERS EOP C04 series data set. You will need to manually update that snapshot to get the most recent data. The sigma for the UT1-TAI value is generally below 1.0 milliseconds after 1980-01-01, and above 1.0 milliseconds before that date.

If you use a date that comes after the range of the downloaded snapshot of the IERS data set, then the timescale conversion code will silently use the most recent value found in the snapshot. If you use a date before 1962-01-01, then the timescale conversion will fail.

You can override all of this logic by using a back-door System property that lets you manually set a specific value for UT1-TAI.

UTC-TAI Is Given A Fixed Value

UTC is the only timescale that uses leap seconds. Leap seconds are problematic.

Superficially they seem simple, but this is misleading. The BIPM is seeking to change things because

"the consequent introduction of leap seconds creates discontinuities that risk causing serious malfunctions in critical digital infrastructure".

Here's an example of a tricky leap second bug.

From the SOFA Cookbook on Time Scales and Calendar Tools:

"Leap seconds pose tricky problems for software writers, and consequently there are concerns that these events put safety-critical systems at risk. The correct solution is for designers to base such systems on TAI or some other glitch-free time scale, not UTC, but this option is often overlooked until it is too late."

Because of their complexity, it's likely that international standards bodies will add no new leap seconds in the future. So, for modern dates and times, UTC will have a fixed offset from TAI. The most recent (and likely the last) leap second was [2016-12-31 23:59:60.0, 2017-01-01 00:00:00.0).

In this library, UTC is implemented as having a simple constant offset from TAI, equal to its current value at the time of writing. That constant offset is hard-coded.

You can override the hard-coded value by using a back-door System property that lets you manually set a specific value for UTC-TAI.

Also Notable

  • in this library, a Date always has a Calendar, and a Time always has a Timescale
  • time zones are not part of this library

What I Learned On This Project

  • clocks on the rotating geoid run all at the same rate! link
  • standards bodies seem to be leaning towards not establishing any more leap seconds.
  • UTC and leaps seconds are the most problematic aspect of timekeeping. They aren't uniform.
  • UTC was introduced January 1, 1960. SOFA states that, strictly speaking, using UTC before this date is dubious.
  • the java.time package has no support for leap seconds.
  • the amount of precision in an IEEE 754 double is not quite enough to model a Julian date precisely. A library that implements arbitrary precision arithmetic (BigDecimal in Java, for example) can solve that.
  • in astronomy, the terms Julian date and Julian calendar are confusing. They refer to separate ideas. A Julian date can be related to different calendars. I had forgotten that.
  • calculations with dates and times are much simplified when you have robust conversions from/to Julian dates. Adding days or seconds no longer needs to deal with calendar logic, because that's done by the robust conversion logic. This only works well when you have the arbitrary precision arithmetic at hand.
  • I found an algorithm for Julian dates that has no restriction to positive Julian dates. This algorithm has been done before, but it doesn't seem to be as popular as it probably should be.
  • The older Network Time Protocal (NTP) has a target precision usually in the millisecond range. The newer Precision Time Protocal (PTP) has a target precision in the nanosecond range, or even better.
  • The second might be re-defined in the future. Newer, more precise clocks are obsoleting the old definition of the second. The new clocks have optical frequencies (~4*10^14 Hz, ~0.000 002ns), not microwave frequencies (~10^10 Hz, ~0.1ns).
  • The world's most accurate clocks can measure the gravitational time-dilation for differences in altitude on the order a 1mm! That precision is just bonkers.