summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjhurst <jhurst@cinecert.com>2008-09-10 22:18:56 +0000
committerjhurst <>2008-09-10 22:18:56 +0000
commit16c33b45f493dc07a64a51473df3b405551385a8 (patch)
tree05cf1a850cf055a65fc8af58baab097feb7a3344 /src
parente07e536da65cc8fd872d32ca201e65dd507f6b51 (diff)
now using libtai for time-date
Diffstat (limited to 'src')
-rwxr-xr-xsrc/KM_fileio.h2
-rw-r--r--src/KM_tai.cpp204
-rw-r--r--src/KM_tai.h104
-rwxr-xr-xsrc/KM_util.cpp113
-rw-r--r--src/Makefile.am2
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, &current);
- time_t adj_time = timegm(&current);
- 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, &current);
- time_t adj_time = timegm(&current);
- 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