I want to convert a time_duration to a DATE format, which is the number of days since 1899, 12, 30.
DATE date_from_duration(time_duration td)
{
double days =
That kind of depends on your circumstances.
The general problem is that 1 / (24. * 60. * 60.)
is not exactly representable as a binary float (because 86400 is not a power of two). The DATE
you get is very nearly exact, but there will be a rounding error. Sometimes this means that it is very little more, sometimes very little less, but there's really not a lot you can do to make it more precise; it is as perfectly alright as you can get. That you see a discrepancy of a second is arguably a problem with your check, in that you stop looking at seconds -- if you check the milliseconds
, you're likely to get 999, making the rounding error look a lot less extreme. This will continue for microseconds
and possibly nanoseconds
, depending on the resolution of time_duration
.
So quite possibly there's nothing to do because the data is alright. If, however, you don't care about milliseconds and beyond and only want the seconds value to be stable in conversions back and forth, the simplest way to achieve that is to add an epsilon value:
DATE date_from_duration(time_duration td)
{
double days =
td.hours () / 24.
+ td.minutes() / (24. * 60.)
+ td.seconds() / (24. * 60. * 60.)
+ 1e-8; // add roughly a millisecond
return days;
}
This increases the overall rounding error but ensures that the error is in a "safe" direction, i.e., that converting it back to time_duration
will give the same seconds()
value and the visible changes will be at the milliseconds()
level.
I might be missing some of the complexity, but it seems really simple to me:
Live On Coliru
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using DATE = double;
boost::posix_time::ptime pTime_from_DATE(double date)
{
static const boost::posix_time::ptime::date_type base_date(1899, boost::gregorian::Dec, 30);
return boost::posix_time::ptime(
base_date,
boost::posix_time::milliseconds(date * 1000 * 60 * 60 * 24));
}
int main() {
boost::posix_time::time_duration duration(1007645, 15, 0);
DATE date = duration.total_milliseconds() / 1000.0 / 60 / 60 / 24;
std::cout << date << ": " << pTime_from_DATE(date);
}
Prints
41985.2: 2014-Dec-12 05:15:00
See it Live On Coliru