#ifndef _utl_TimeStamp_h_ #define _utl_TimeStamp_h_ #include #include #include #include struct tm; namespace utl { class TimeInterval; /** \class TimeStamp TimeStamp.h "utl/TimeStamp.h" \brief A TimeStamp holds GPS second and nanosecond for some event
  • \ref intro "Introduction"
  • \ref conventions "Different time conventions"
  • \ref unix "Why not just use unix time_t?"
\anchor intro

Introduction

This class holds a GPS second and nanosecond and provides methods to convert to seconds since Unix Epoch or to UTC, with proper accounting for leap seconds. Methods are also provided to return Modified Julian Date and formatted strings with UTC printout consistent with the conventions document, as well as strings of XML with date and time information. A utl::TimeStamp represents the time of occurrence of some event. To represent time intervals between events, use the TimeInterval class. A number of arithmetic operations are defined between utl::TimeStamp and utl::TimeInterval. For example: \verbatim TimeStamp - TimeStamp = TimeInterval TimeStamp - TimeInterval = TimeStamp TimeStamp + TimeInterval = TimeStamp TimeInterval + TimeInterval = TimeInterval \endverbatim \anchor conventions

Time conventions

What is time? This is a brief summary of time systems, relevant for the Auger project operation (see http://tycho.usno.navy.mil/gpstt.html for details).

  • International Atomic Time (TAI) is a statistical time scale based on a large number of atomic clocks operating at standards laboratories around the world. Its unit interval is exactly one SI second at sea level. Neglecting the relativistic effects, this is probably the time scale in which Auger physics is happening.
  • Universal Time (UT) (and its variant UT1) is a time scale with unit of duration the mean solar day. It is based on the Earth's rotation and thus important for transformation of events into the galactic coordinates. Otherwise, not very useful for physics.
  • Coordinated Universal Time (UTC) differs from TAI by an integral number of seconds. UTC is kept within 0.9 seconds of UT1 by the introduction of one-second steps to UTC, the leap seconds. In contrast to UT1, UTC is running in parallel to TAI with piecewise constant offset.
  • Global Positioning System (GPS) time is synchronized to UTC but it is NOT adjusted for leap seconds. Since TAI and GPS epoch did not start on the same date, they run in parallel with TAI ahead of GPS by (constant) 19 seconds. GPS thus can be a candidate for physics time scale.
\anchor unix

Why not just use unix time?

The utl::TimeStamp class will not allow you to initialize a TimeStamp using a unix time_t. You may wonder why this is, or wonder why we don't just use unix time for everything, since the c time library has functions already built in for converting unix seconds to UTC. The reason is that, in a nutshell, unix time is broken. For some reason the POSIX standard requires the time_t to count seconds since Unix epoch not including leap seconds. This means calculating time intervals by subtracting unix times across a leap second will give the wrong result. Furthermore, initializing a TimeStamp with a time_t at the leap second boundary would be ambiguous; there are two GPS seconds corresponding to the unix second at the time of the leap second. It may seem that this would only rarely pose a problem, but on the other hand it is not particularly difficult to just do it correctly. \author T. Paul \author D. Veberic \date 19 Feb 2003 \version $Id$ \ingroup time */ class TimeStamp : public SafeBoolCast { public: TimeStamp() : fGPSSecond(0), fGPSNanoSecond(0) { } /// Construct from GPS second and nanosecond TimeStamp(const long sec, const double nsec = 0) { SetNormalized(sec, nsec); } /// Set GPS second and (optionally) nanosecond void SetGPSTime(const unsigned long sec, const double nsec = 0) { SetNormalized(sec, nsec); } /// GPS second unsigned long GetGPSSecond() const { return fGPSSecond; } /// GPS nanosecond double GetGPSNanoSecond() const { return fGPSNanoSecond; } // --------------------- // Arithmetic operations // --------------------- /// [TimeStamp] + [TimeInterval] = [TimeStamp] TimeStamp operator+(const TimeInterval& ti) const; /// [TimeStamp] += [TimeInterval] = [TimeStamp] TimeStamp& operator+=(const TimeInterval& ti); /// [TimeStamp] - [TimeStamp] = [TimeInterval] TimeInterval operator-(const TimeStamp& ts) const; /// [TimeStamp] - [TimeInterval] = [TimeStamp] TimeStamp operator-(const TimeInterval& ti) const; /// [TimeStamp] -= [TimeInterval] = [TimeStamp] TimeStamp& operator-=(const TimeInterval& ti); // ------------------ // Boolean operations // ------------------ bool operator==(const TimeStamp& ts) const { return (fGPSSecond == ts.fGPSSecond && fGPSNanoSecond == ts.fGPSNanoSecond); } bool operator!=(const TimeStamp& ts) const { return !operator==(ts); } bool operator>(const TimeStamp& ts) const { return (fGPSSecond > ts.fGPSSecond || (fGPSSecond == ts.fGPSSecond && fGPSNanoSecond > ts.fGPSNanoSecond)); } bool operator>=(const TimeStamp& ts) const { return !operator<(ts); } bool operator<(const TimeStamp& ts) const { return (fGPSSecond < ts.fGPSSecond || (fGPSSecond == ts.fGPSSecond && fGPSNanoSecond < ts.fGPSNanoSecond)); } bool operator<=(const TimeStamp& ts) const { return !operator>(ts); } bool BoolCast() const { return fGPSSecond || fGPSNanoSecond; } static TimeStamp Max() { return TimeStamp(2147483647UL, 999999999.9999999); } private: // with this we will have a y2k problem in approx. 136 years - // or for some operations in 68 years - from 1980 (GPS epoch) unsigned long fGPSSecond; double fGPSNanoSecond; /// Take care of positive nanosecond and GPS epoch void SetNormalized(long sec, double nsec); }; /// get current time as reported by system TimeStamp GetCurrentSystemTime(); std::ostream& operator<<(std::ostream& os, const TimeStamp& ts); } // the following has to be done in this manner in order to keep // some important operators inline #include #include namespace utl { inline TimeStamp TimeStamp::operator+(const TimeInterval& ti) const { // proper normalization is done by the TimeStamp ctor return TimeStamp(long(fGPSSecond + ti.GetSecond()), fGPSNanoSecond + ti.GetNanoSecond()); } inline TimeStamp& TimeStamp::operator+=(const TimeInterval& ti) { SetNormalized(fGPSSecond + ti.GetSecond(), fGPSNanoSecond + ti.GetNanoSecond()); return *this; } inline TimeInterval TimeStamp::operator-(const TimeStamp& ts) const { return TimeInterval( (long(fGPSSecond) - long(ts.fGPSSecond)) * second + (fGPSNanoSecond - ts.fGPSNanoSecond) * nanosecond ); } inline TimeStamp TimeStamp::operator-(const TimeInterval& ti) const { // proper normalization is done by the TimeStamp ctor return TimeStamp(long(fGPSSecond) - long(ti.GetSecond()), fGPSNanoSecond - ti.GetNanoSecond()); } inline TimeStamp& TimeStamp::operator-=(const TimeInterval& ti) { SetNormalized(long(fGPSSecond) - long(ti.GetSecond()), fGPSNanoSecond - ti.GetNanoSecond()); return *this; } } #endif