From 70381675820415d2255fda9f947a9ea0933e9cdb Mon Sep 17 00:00:00 2001 From: Constantin Michael Date: Sun, 4 Dec 2011 23:29:59 +0200 Subject: Improve PostgreSQL boost date-time mappings to handle microsecond resolution Note that these changes also remove the limitation for minimum and maximum date times imposed by the Boost 64 bit std::time_t implementation. The ptime mapping no longer utilizes the Boost std::time_t interface. --- odb/boost/date-time/pgsql/posix-time-traits.hxx | 56 +++++++++++++++---------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/odb/boost/date-time/pgsql/posix-time-traits.hxx b/odb/boost/date-time/pgsql/posix-time-traits.hxx index 375a5e4..b3a2e43 100644 --- a/odb/boost/date-time/pgsql/posix-time-traits.hxx +++ b/odb/boost/date-time/pgsql/posix-time-traits.hxx @@ -8,10 +8,7 @@ #include -#include - #include -#include // from_time_t #include #include @@ -38,11 +35,6 @@ namespace odb typedef ptime query_type; typedef long long image_type; - // The difference between the Unix epoch and the PostgreSQL epoch - // in seconds. - // - static const long long epoch_diff = 946684800LL; - static const long long neg_inf = -0x7fffffffffffffffLL - 1; static const long long pos_inf = 0x7fffffffffffffffLL; @@ -60,8 +52,27 @@ namespace odb else if (i == pos_inf) v = ptime (::boost::date_time::pos_infin); else - v = ::boost::posix_time::from_time_t ( - static_cast (i / 1000000 + epoch_diff)); + { + const ptime pg_epoch (date (2000, 1, 1), + time_duration (0, 0, 0)); + + // We need to split the microsecond image into hours and + // microseconds to avoid overflow during the fractional seconds + // calculation. + // + time_duration::hour_type h ( + static_cast (i / 3600000000LL)); + + i -= static_cast (h) * 3600000000LL; + + v = pg_epoch + + time_duration ( + h, + 0, + 0, + static_cast ( + i * time_duration::ticks_per_second () / 1000000LL)); + } } } @@ -83,20 +94,15 @@ namespace odb } else { - const ptime unix_epoch (date (1970, 1, 1), time_duration (0, 0, 0)); - - long long pg_seconds ( - static_cast ( - (v - unix_epoch).ticks () / time_duration::ticks_per_second ()) - - epoch_diff); - - i = endian_traits::hton (pg_seconds * 1000000); + const ptime pg_epoch (date (2000, 1, 1), time_duration (0, 0, 0)); + i = endian_traits::hton ( + static_cast ((v - pg_epoch).total_microseconds ())); } } }; // Implementation of the mapping between boost::posix_time::time_duration - // and PostgreSQL TIME. The TIME values are stores as micro-seconds since + // and PostgreSQL TIME. The TIME values are stored as micro-seconds since // 00:00:00. // template <> @@ -116,9 +122,13 @@ namespace odb if (is_null) v = time_duration (::boost::date_time::not_a_date_time); else - v = time_duration (0, 0, - static_cast ( - endian_traits::ntoh (i) / 1000000)); + v = time_duration ( + 0, + 0, + 0, + static_cast ( + endian_traits::ntoh (i) * time_duration::ticks_per_second () / + 1000000LL)); } static void @@ -137,7 +147,7 @@ namespace odb { is_null = false; i = endian_traits::hton ( - static_cast (v.total_seconds ()) * 1000000); + static_cast (v.total_microseconds ())); } } }; -- cgit v1.1