Distributed Information System (DIS)
  • Home
  • The blog
  • Contact

Presenting the Timez data type

9/21/2015

0 Comments

 
I'm currently working on an implementation of the Date Time stamp I described in this post and that I decided to name Timez. It seamed trivial to implement at first, but I then discovered the particular property of the system time regarding leap seconds and the problem it represent.

Before explaining the problem, let me briefly explain what a Timez is. The idea is simple but brilliant (thanks).
Photo
Clocks displaying local time of different location of the world. [http://sapling-inc.com]

The Timez stamp

A time stamp is generated at a particular location on the surface of the globe. It thus have a specific local time offset relative to the UTC time. A user in a different time zone may want to
  1. view the stamp time with the local time where it was produced ;
  2. sort stamps by UTC time, thus ignoring the local time offset of its origin ;
  3. view the stamp time with his own local time offset  ;
  4. view the stamp time with the local time offset of another location in the world.  
Use cases are for instance a web forum with messages of people from different time zone. Messages have to be sorted by time regardless of the senders local time offset. etc. Another use case is a messaging system like mail. ISO 8601 defines a standard ASCII time representation convenient for humans, but its not compact and efficient.

The solution I came up with is to combine into a 64 bit signed integer a time expressed as the number of micro seconds relative to an epoch and the local time offset expressed as a number of minutes where the stamp was generated.
Picture
The number of micro seconds is a signed integer. When it is negative, it represents the number of micro seconds left to elapse to reach the epoch. When positive, it is the number of micro seconds elapsed since the epoch. The time range covered by this value is +/- 142 years relative to the epoch's year.

The time offset is an unsigned integer. It's the time offset plus 1024, and its range is +/- 17 hours (+/-1023 minutes). If the bits of the time offset field are all zero, the time offset value is -1024 and the Timez value is invalid or undefined.

Up to here, it's all simple and straightforward. So I started implementing the Timez data type in C.

Time in Timez is without leap seconds correction

The time without leap second correction is called the TAI (International Atomic Time) time. The GPS (Global Positioning System) time is also uncorrected by leap second. They differ by their epoch only. I decided that Timez refers to these clocks to avoid the problems resulting from the leap second correction.

But to my big surprise, there is actually no way to get the time in POSIX (all Unix flavors) or Windows without leap second corrections a.k.a. TAI or GPS time. The system time you get with the functions time(), gettimeofday() or  clock_gettime() is the number of seconds elapsed since the 1970-01-01T00:00:00 UTC minus the leap seconds.

Investigating this further, it appears that the time handling problem on computers is actually a rabbit hole. I learned a lot in the process, but also wasted a significant amount of time. It is frustrating because it clearly result from standard definition and support lagging.

Happily, things are slowly changing, but only very slowly. Since Linux Kernel 3.10 there is a new clock id that can be used by clock_gettime() named CLOCK_TAI. But on my computer it currently still returns the same time as CLOCK_REALTIME. Apparently you need a version of NTP higher than 4.2.6 to get the CLOCK_TAI clock adjusted.

What is then still missing is a conversion between leap second corrected time and uncorrected time. I plan to provide such function so that Timez can be used with operating systems that don't provide TAI or GPS time. I'll unfortunately have to hard code the table of leap seconds because there is no easy access to a dynamically updated table.

If you want to learn more about leap seconds I suggest to read this section in Wikipedia.  An interesting part is about the proposal to drop the leap second correction. I also encourage you look see this short video on the Time & Time zone problem from the Computerphile.

The epoch of Timez

This was a difficult decision to make. CLOCK_TAI is using the epoch 1970-01-01T00:00:00 UTC as CLOCK_REALTIME. This means that negative count of seconds cover the period before this epoch. With 64bit integers to encode the court of seconds, this is not a problem.

With 53 bits encoding the number of microseconds, we are short. We can only cover +/- 142 years around the epoch. By picking the same epoch as CLOCK_TAI we would only have ~100 years left until the Timez time counter would wrap.

I then identified three options.
  1. Epoch = 1970-01-01T00:00:00 UTC + 2^52 : the covered time range is then from 1970 to 2254 ;
  2. Epoch = 2050-01-01T00:00:00 TAI : the covered time range is then from 1908 to 2192 ;
  3. Epoch = 1970-01-01T00:00:00 UTC + 2^52 - (2^31) * 1000000: the covered time range is then from 1902 to 2186.

Option 1 would have the advantage to push the wrapping limit the farther away in the future. The disadvantage is that it can't represent time before 1970. The epoch offset is a value easy to remember.

Option 2 would have the advantage to allow representing time in the past. But the epoch offset would be an obscure integer magic number corresponding to the number of micro seconds between 1970 and 2150.
 
Option 3 has the advantage to cover the time span of 32 bit signed integer time_t value. The Timez would thus be backward compatible with the time_t values. The epoch offset is still a magic word but more easily obtained than the one of option 2. However, conversion between corrected and uncorrected time is not well defined before 1972.

Considering the pros and cons of the different options, I choose option 2. The Timez epoch is 1970-01-01T00:00:00 UTC + 2^52. The value 2^52 is the timez epoch offset relative to the POSIX time epoch. Note that 1970-01-01T00:00:00 UTC is 1970-01-01T00:00:10 TAI.

To convert a CLOCK_TAI value to a Timez micro second count use the following expression :
#define TIMEZ_EPOCH 0x10000000000000LL
struct timespec tp;
if (clock_gettime(CLOCK_TAI, &tp) ) /*fail*/ ;
int64_t t = tp.tv_sec * 1000000 + tp.tv_nsec / 1000 - TIMEZ_EPOCH;
0 Comments



Leave a Reply.

    Author

    Christophe Meessen is a  computer science engineer working in France.

    Any suggestions to make DIS more useful ? Tell me by using the contact page.

    Categories

    All
    Business Model
    Database
    Dis
    Ditp
    Dvcs
    Git
    Gob
    Idr
    Misc
    Murphys Law
    Programming Language
    Progress Status
    Startup
    Suggested Reading
    Web Site

    Archives

    December 2017
    November 2015
    September 2015
    February 2013
    December 2012
    November 2012
    May 2012
    February 2012
    March 2010
    October 2009
    September 2009
    July 2009
    June 2009
    May 2009
    February 2009
    January 2009
    November 2008
    September 2008
    August 2008
    July 2008
    May 2008
    April 2008
    March 2008
    February 2008
    January 2008
    December 2007
    October 2007
    August 2007
    July 2007
    June 2007
    May 2007

    RSS Feed

    Live traffic feed
    You have no departures or arrivals yet. Wait a few minutes and check again.
    Powered by FEEDJIT
Powered by Create your own unique website with customizable templates.