aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-12-04 23:29:59 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-12-05 11:29:55 +0200
commit70381675820415d2255fda9f947a9ea0933e9cdb (patch)
tree96c79549a1ab2429b3ebc9c52edd90ef970c5395
parent14d3c1da7bb4e7781d16a18d22b94b30c23f6cee (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.hxx56
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 ()));
}
}
};