diff options
author | Constantin Michael <constantin@codesynthesis.com> | 2011-12-04 23:29:59 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2011-12-05 11:29:55 +0200 |
commit | 70381675820415d2255fda9f947a9ea0933e9cdb (patch) | |
tree | 96c79549a1ab2429b3ebc9c52edd90ef970c5395 | |
parent | 14d3c1da7bb4e7781d16a18d22b94b30c23f6cee (diff) |
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.
-rw-r--r-- | odb/boost/date-time/pgsql/posix-time-traits.hxx | 56 |
1 files 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 <odb/pre.hxx> -#include <ctime> - #include <boost/date_time/posix_time/posix_time_types.hpp> -#include <boost/date_time/posix_time/conversion.hpp> // from_time_t #include <odb/core.hxx> #include <odb/pgsql/traits.hxx> @@ -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<std::time_t> (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<time_duration::hour_type> (i / 3600000000LL)); + + i -= static_cast<long long> (h) * 3600000000LL; + + v = pg_epoch + + time_duration ( + h, + 0, + 0, + static_cast<time_duration::fractional_seconds_type> ( + 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<long long> ( - (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<long long> ((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<long> ( - endian_traits::ntoh (i) / 1000000)); + v = time_duration ( + 0, + 0, + 0, + static_cast<time_duration::fractional_seconds_type> ( + 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<long long> (v.total_seconds ()) * 1000000); + static_cast<long long> (v.total_microseconds ())); } } }; |