diff options
| author | jhurst <jhurst@cinecert.com> | 2008-09-10 22:18:56 +0000 |
|---|---|---|
| committer | jhurst <> | 2008-09-10 22:18:56 +0000 |
| commit | 16c33b45f493dc07a64a51473df3b405551385a8 (patch) | |
| tree | 05cf1a850cf055a65fc8af58baab097feb7a3344 /src | |
| parent | e07e536da65cc8fd872d32ca201e65dd507f6b51 (diff) | |
now using libtai for time-date
Diffstat (limited to 'src')
| -rwxr-xr-x | src/KM_fileio.h | 2 | ||||
| -rw-r--r-- | src/KM_tai.cpp | 204 | ||||
| -rw-r--r-- | src/KM_tai.h | 104 | ||||
| -rwxr-xr-x | src/KM_util.cpp | 113 | ||||
| -rw-r--r-- | src/Makefile.am | 2 |
5 files changed, 376 insertions, 49 deletions
diff --git a/src/KM_fileio.h b/src/KM_fileio.h index 141ca58..1376716 100755 --- a/src/KM_fileio.h +++ b/src/KM_fileio.h @@ -102,7 +102,7 @@ namespace Kumu // // error: 'void Kumu::compile_time_size_checker() [with bool sizecheck = false]' previously declared here // - // This is happeining because the equality being tested below is false. The reason for this + // This is happening because the equality being tested below is false. The reason for this // will depend on your OS, but on Linux it is probably because you have not used -D_FILE_OFFSET_BITS=64 // Adding this magic macro to your CFLAGS will get you going again. If you are on a system that // does not support 64-bit files, you can disable this check by using -DKM_SMALL_FILES_OK. You diff --git a/src/KM_tai.cpp b/src/KM_tai.cpp new file mode 100644 index 0000000..7aa7ada --- /dev/null +++ b/src/KM_tai.cpp @@ -0,0 +1,204 @@ +/* + +THIS IS A SUBSET OF THE FULL LIBTAI. CHANGES HAVE BEEN MADE TO SUIT +LIBKUMU STYLE AND TYPE CONVENTIONS. ALL BUGS BELONG TO JOHN HURST. +THE FOLLOWING IS FOR ATTRIBUTION, THANK YOU MR. BERNSTEIN FOR WRITING +AND DISTRIBUTING SUCH GREAT SOFTWARE: + +libtai 0.60, alpha. +19981013 +Copyright 1998 +D. J. Bernstein, djb@pobox.com +http://pobox.com/~djb/libtai.html + + +libtai is a library for storing and manipulating dates and times. + +libtai supports two time scales: (1) TAI64, covering a few hundred +billion years with 1-second precision; (2) TAI64NA, covering the same +period with 1-attosecond precision. Both scales are defined in terms of +TAI, the current international real time standard. + +libtai provides an internal format for TAI64, struct tai, designed for +fast time manipulations. The tai_pack() and tai_unpack() routines +convert between struct tai and a portable 8-byte TAI64 storage format. +libtai provides similar internal and external formats for TAI64NA. + +libtai provides struct caldate to store dates in year-month-day form. It +can convert struct caldate, under the Gregorian calendar, to a modified +Julian day number for easy date arithmetic. + +libtai provides struct caltime to store calendar dates and times along +with UTC offsets. It can convert from struct tai to struct caltime in +UTC, accounting for leap seconds, for accurate date and time display. It +can also convert back from struct caltime to struct tai for user input. +Its overall UTC-to-TAI conversion speed is 100x better than the usual +UNIX mktime() implementation. + +This version of libtai requires a UNIX system with gettimeofday(). It +will be easy to port to other operating systems with compilers +supporting 64-bit arithmetic. + +The libtai source code is in the public domain. + +*/ + + /*! \file KM_tai.cpp + \version $Id$ + \brief portable time functions + */ + +#include <KM_tai.h> +#include <sys/time.h> + +// +void +caldate_frommjd(Kumu::TAI::caldate* cd, i32_t day) +{ + i32_t year, month, yday; + + year = day / 146097L; + day %= 146097L; + day += 678881L; + while (day >= 146097L) { day -= 146097L; ++year; } + + /* year * 146097 + day - 678881 is MJD; 0 <= day < 146097 */ + /* 2000-03-01, MJD 51604, is year 5, day 0 */ + + year *= 4; + if (day == 146096L) { year += 3; day = 36524L; } + else { year += day / 36524L; day %= 36524L; } + year *= 25; + year += day / 1461; + day %= 1461; + year *= 4; + + yday = (day < 306); + if (day == 1460) { year += 3; day = 365; } + else { year += day / 365; day %= 365; } + yday += day; + + day *= 10; + month = (day + 5) / 306; + day = (day + 5) % 306; + day /= 10; + if (month >= 10) { yday -= 306; ++year; month -= 10; } + else { yday += 59; month += 2; } + + cd->year = year; + cd->month = month + 1; + cd->day = day + 1; +} + +// +static ui32_t times365[4] = { 0, 365, 730, 1095 } ; +static ui32_t times36524[4] = { 0, 36524UL, 73048UL, 109572UL } ; +static ui32_t montab[12] = +{ 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 } ; +/* month length after february is (306 * m + 5) / 10 */ + +// +i32_t +caldate_mjd(const Kumu::TAI::caldate* cd) +{ + i32_t y, m, d; + + d = cd->day - 678882L; + m = cd->month - 1; + y = cd->year; + + d += 146097L * (y / 400); + y %= 400; + + if (m >= 2) m -= 2; else { m += 10; --y; } + + y += (m / 12); + m %= 12; + if (m < 0) { m += 12; --y; } + + d += montab[m]; + + d += 146097L * (y / 400); + y %= 400; + if (y < 0) { y += 400; d -= 146097L; } + + d += times365[y & 3]; + y >>= 2; + + d += 1461L * (y % 25); + y /= 25; + + d += times36524[y & 3]; + + return d; +} + + +// +void +caltime_utc(Kumu::TAI::caltime* ct, const Kumu::TAI::tai* t) +{ + Kumu::TAI::tai t2 = *t; + ui64_t u; + i32_t s; + + /* XXX: check for overfow? */ + + u = t2.x; + + u += 58486; + s = u % ui64_C(86400); + + ct->second = (s % 60); s /= 60; + ct->minute = s % 60; s /= 60; + ct->hour = s; + + u /= ui64_C(86400); + caldate_frommjd(&ct->date,/*XXX*/(i32_t) (u - ui64_C(53375995543064))); + + ct->offset = 0; +} + +// +void +caltime_tai(const Kumu::TAI::caltime* ct, Kumu::TAI::tai* t) +{ + i32_t day, s; + + /* XXX: check for overflow? */ + + day = caldate_mjd(&ct->date); + + s = ct->hour * 60 + ct->minute; + s = (s - ct->offset) * 60 + ct->second; + + t->x = day * ui64_C(86400) + ui64_C(4611686014920671114) + (i64_t)s; +} + +// +void +Kumu::TAI::tai::now() +{ + struct timeval now; + gettimeofday(&now, 0); + x = ui64_C(4611686018427387914) + (ui64_t)now.tv_sec; +} + +// +const Kumu::TAI::tai& +Kumu::TAI::tai::operator=(const Kumu::TAI::caltime& rhs) +{ + caltime_tai(&rhs, this); +} + +// +const Kumu::TAI::caltime& +Kumu::TAI::caltime::operator=(const Kumu::TAI::tai& rhs) +{ + caltime_utc(this, &rhs); +} + + +// +// end KM_tai.cpp +// diff --git a/src/KM_tai.h b/src/KM_tai.h new file mode 100644 index 0000000..63336e7 --- /dev/null +++ b/src/KM_tai.h @@ -0,0 +1,104 @@ +/* + +THIS IS A SUBSET OF THE FULL LIBTAI. CHANGES HAVE BEEN MADE TO SUIT +LIBKUMU STYLE AND TYPE CONVENTIONS. ALL BUGS BELONG TO JOHN HURST. +THE FOLLOWING IS FOR ATTRIBUTION, THANK YOU MR. BERNSTEIN FOR WRITING +AND DISTRIBUTING SUCH GREAT SOFTWARE: + +libtai 0.60, alpha. +19981013 +Copyright 1998 +D. J. Bernstein, djb@pobox.com +http://pobox.com/~djb/libtai.html + + +libtai is a library for storing and manipulating dates and times. + +libtai supports two time scales: (1) TAI64, covering a few hundred +billion years with 1-second precision; (2) TAI64NA, covering the same +period with 1-attosecond precision. Both scales are defined in terms of +TAI, the current international real time standard. + +libtai provides an internal format for TAI64, struct tai, designed for +fast time manipulations. The tai_pack() and tai_unpack() routines +convert between struct tai and a portable 8-byte TAI64 storage format. +libtai provides similar internal and external formats for TAI64NA. + +libtai provides struct caldate to store dates in year-month-day form. It +can convert struct caldate, under the Gregorian calendar, to a modified +Julian day number for easy date arithmetic. + +libtai provides struct caltime to store calendar dates and times along +with UTC offsets. It can convert from struct tai to struct caltime in +UTC, accounting for leap seconds, for accurate date and time display. It +can also convert back from struct caltime to struct tai for user input. +Its overall UTC-to-TAI conversion speed is 100x better than the usual +UNIX mktime() implementation. + +This version of libtai requires a UNIX system with gettimeofday(). It +will be easy to port to other operating systems with compilers +supporting 64-bit arithmetic. + +The libtai source code is in the public domain. + +*/ + + /*! \file KM_tai.h + \version $Id$ + \brief portable time functions + */ + +#ifndef _KUMU_TAI_H_ +#define _KUMU_TAI_H_ + +#include <KM_platform.h> + +// +namespace Kumu +{ + namespace TAI + { + class caltime; + + // + struct tai + { + ui64_t x; + inline void add_hours(i32_t h) { x += h * 3600; } + inline void add_days(i32_t h) { x += h * 86400; } + void now(); + + const tai& operator=(const caltime& rhs); + }; + + // + struct caldate + { + i32_t year; + i32_t month; + i32_t day; + }; + + // + struct caltime + { + caldate date; + i32_t hour; + i32_t minute; + i32_t second; + i32_t offset; + + const caltime& operator=(const tai& rhs); + }; + + + } // namespace TAI + +} // namespace Kumu + + +#endif // _KUMU_TAI_H_ + +// +// end KM_tai.h +// diff --git a/src/KM_util.cpp b/src/KM_util.cpp index b12d702..46dbfa6 100755 --- a/src/KM_util.cpp +++ b/src/KM_util.cpp @@ -34,6 +34,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <KM_memio.h> #include <KM_fileio.h> #include <KM_log.h> +#include <KM_tai.h> #include <ctype.h> #include <list> #include <map> @@ -720,64 +721,80 @@ Kumu::Timestamp::AddHours(i32_t hours) #include <time.h> -#define TIMESTAMP_TO_TM(ts, t) \ - (t)->tm_year = (ts).Year - 1900; /* year - 1900 */ \ - (t)->tm_mon = (ts).Month - 1; /* month of year (0 - 11) */ \ - (t)->tm_mday = (ts).Day; /* day of month (1 - 31) */ \ - (t)->tm_hour = (ts).Hour; /* hours (0 - 23) */ \ - (t)->tm_min = (ts).Minute; /* minutes (0 - 59) */ \ - (t)->tm_sec = (ts).Second; /* seconds (0 - 60) */ - -#define TM_TO_TIMESTAMP(t, ts) \ - (ts).Year = (t)->tm_year + 1900; /* year - 1900 */ \ - (ts).Month = (t)->tm_mon + 1; /* month of year (0 - 11) */ \ - (ts).Day = (t)->tm_mday; /* day of month (1 - 31) */ \ - (ts).Hour = (t)->tm_hour; /* hours (0 - 23) */ \ - (ts).Minute = (t)->tm_min; /* minutes (0 - 59) */ \ - (ts).Second = (t)->tm_sec; /* seconds (0 - 60) */ +#define TIMESTAMP_TO_CALTIME(ts, ct) \ + (ct)->date.year = (ts).Year; /* year */ \ + (ct)->date.month = (ts).Month; /* month of year (1 - 12) */ \ + (ct)->date.day = (ts).Day; /* day of month (1 - 31) */ \ + (ct)->hour = (ts).Hour; /* hours (0 - 23) */ \ + (ct)->minute = (ts).Minute; /* minutes (0 - 59) */ \ + (ct)->second = (ts).Second; /* seconds (0 - 60) */ \ + (ct)->offset = 0; + +#define CALTIME_TO_TIMESTAMP(ct, ts) \ + assert((ct)->offset == 0); \ + (ts).Year = (ct)->date.year; /* year */ \ + (ts).Month = (ct)->date.month; /* month of year (1 - 12) */ \ + (ts).Day = (ct)->date.day; /* day of month (1 - 31) */ \ + (ts).Hour = (ct)->hour; /* hours (0 - 23) */ \ + (ts).Minute = (ct)->minute; /* minutes (0 - 59) */ \ + (ts).Second = (ct)->second; /* seconds (0 - 60) */ + // Kumu::Timestamp::Timestamp() : - Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0) + Year(0), Month(0), Day(0), Hour(0), Minute(0), Second(0) { - time_t t_now = time(0); - struct tm* now = gmtime(&t_now); - TM_TO_TIMESTAMP(now, *this); + Kumu::TAI::tai now; + Kumu::TAI::caltime ct; + now.now(); + ct = now; + CALTIME_TO_TIMESTAMP(&ct, *this) } // bool Kumu::Timestamp::operator<(const Timestamp& rhs) const { - struct tm lhtm, rhtm; - TIMESTAMP_TO_TM(*this, &lhtm); - TIMESTAMP_TO_TM(rhs, &rhtm); - return ( timegm(&lhtm) < timegm(&rhtm) ); + Kumu::TAI::caltime lh_ct, rh_ct; + TIMESTAMP_TO_CALTIME(*this, &lh_ct) + TIMESTAMP_TO_CALTIME(rhs, &rh_ct) + + Kumu::TAI::tai lh_tai, rh_tai; + lh_tai = lh_ct; + rh_tai = rh_ct; + + return ( lh_tai.x < rh_tai.x ); } // bool Kumu::Timestamp::operator>(const Timestamp& rhs) const { - struct tm lhtm, rhtm; - TIMESTAMP_TO_TM(*this, &lhtm); - TIMESTAMP_TO_TM(rhs, &rhtm); - return ( timegm(&lhtm) > timegm(&rhtm) ); + Kumu::TAI::caltime lh_ct, rh_ct; + TIMESTAMP_TO_CALTIME(*this, &lh_ct) + TIMESTAMP_TO_CALTIME(rhs, &rh_ct) + + Kumu::TAI::tai lh_tai, rh_tai; + lh_tai = lh_ct; + rh_tai = rh_ct; + + return ( lh_tai.x > rh_tai.x ); } // void Kumu::Timestamp::AddDays(i32_t days) { - struct tm current; + Kumu::TAI::caltime ct; + Kumu::TAI::tai t; if ( days != 0 ) { - TIMESTAMP_TO_TM(*this, ¤t); - time_t adj_time = timegm(¤t); - adj_time += 86400 * days; - struct tm* now = gmtime(&adj_time); - TM_TO_TIMESTAMP(now, *this); + TIMESTAMP_TO_CALTIME(*this, &ct) + t = ct; + t.add_days(days); + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) } } @@ -785,15 +802,16 @@ Kumu::Timestamp::AddDays(i32_t days) void Kumu::Timestamp::AddHours(i32_t hours) { - struct tm current; + Kumu::TAI::caltime ct; + Kumu::TAI::tai t; if ( hours != 0 ) { - TIMESTAMP_TO_TM(*this, ¤t); - time_t adj_time = timegm(¤t); - adj_time += 3600 * hours; - struct tm* now = gmtime(&adj_time); - TM_TO_TIMESTAMP(now, *this); + TIMESTAMP_TO_CALTIME(*this, &ct) + t = ct; + t.add_hours(hours); + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) } } @@ -932,7 +950,7 @@ Kumu::Timestamp::DecodeString(const char* datestr) ui32_t TZ_mm = atoi(datestr + 23); if ( TZ_mm != 0 ) - DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm); + Kumu::DefaultLogSink().Warn("Ignoring minutes in timezone offset: %u\n", TZ_mm); if ( TZ_hh > 12 ) return false; @@ -944,8 +962,8 @@ Kumu::Timestamp::DecodeString(const char* datestr) if ( datestr[char_count] != 0 ) { - DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n", - datestr, char_count); + Kumu::DefaultLogSink().Error("Unexpected extra characters in string: %s (%ld)\n", + datestr, char_count); return false; } @@ -957,11 +975,12 @@ Kumu::Timestamp::DecodeString(const char* datestr) return false; SYSTIME_TO_TIMESTAMP(&st, *this); #else - struct tm stm; - TIMESTAMP_TO_TM(TmpStamp, &stm); - if ( timegm(&stm) == 0 ) - return false; - TM_TO_TIMESTAMP(&stm, *this); + Kumu::TAI::tai t; + Kumu::TAI::caltime ct; + TIMESTAMP_TO_CALTIME(TmpStamp, &ct); + t = ct; // back and forth to tai to normalize offset + ct = t; + CALTIME_TO_TIMESTAMP(&ct, *this) #endif return true; diff --git a/src/Makefile.am b/src/Makefile.am index 00a4ede..a4bd25a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,7 +41,7 @@ lib_LTLIBRARIES = libkumu.la libasdcp.la # sources for a library libkumu_la_SOURCES = KM_error.h KM_fileio.cpp KM_fileio.h KM_log.cpp KM_log.h \ KM_memio.h KM_mutex.h KM_platform.h KM_prng.cpp KM_prng.h KM_util.cpp \ - KM_util.h KM_xml.cpp KM_xml.h + KM_util.h KM_xml.cpp KM_xml.h KM_tai.h KM_tai.cpp # linker flags (*not* including libraries to link against) for a library libkumu_la_LDFLAGS = -version-info 3:19:0 # sources for a library that don't get added to a distribution |
