我想将time_duration格式转换为DATE格式,即自1899年12月30日以来的天数。
DATE date_from_duration(time_duration td)
{
double days = td.hours()/24.+td.minutes()/(24.*60.)+td.seconds()/(24.*60.*60.);
return days;
}
此代码几乎可以正常运行,但有时会出现舍入错误,time_duration(1007645, 15, 0)
应该会在2014-12-12 00:15:00生成,但实际上是2014-12-12 00:14:59。
使用此方法检查DATE,从here
中窃取ptime pTime_from_DATE(double date)
{
using boost::math::modf;
static const ptime::date_type base_date(1899, Dec, 30);
static const ptime base_time(base_date, ptime::time_duration_type(0,0,0));
int dayOffset, hourOffset, minuteOffset, secondOffset;
double fraction = fabs(modf(date, &dayOffset)) * 24; // fraction = hours
fraction = modf(fraction, &hourOffset) * 60; // fraction = minutes
fraction = modf(fraction, &minuteOffset) * 60; // fraction = seconds
modf(fraction, &secondOffset);
ptime t(base_time);
t += ptime::time_duration_type(hourOffset, minuteOffset, secondOffset);
t += ptime::date_duration_type(dayOffset);
return t;
}
如何有效地纠正这种舍入问题?
答案 0 :(得分:1)
我可能会错过一些复杂性,但对我来说似乎很简单:
的 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);
}
打印
41985.2: 2014-Dec-12 05:15:00
答案 1 :(得分:0)
这取决于你的情况。
一般问题是1 / (24. * 60. * 60.)
不能完全表示为二进制浮点数(因为86400不是2的幂)。你得到的DATE
非常精确,但会出现舍入错误。有时候这意味着它会更多,有时甚至更少,但实际上并没有太多可以让它更精确;它就像你能得到的一样完美。您看到一秒钟的差异可以说是您的支票存在问题,因为您停止查看秒数 - 如果您检查milliseconds
,您可能会得到999,这使得舍入错误看起来很多不太极端。这将继续microseconds
,可能会nanoseconds
,具体取决于time_duration
的解决方案。
所以很可能无事可做,因为数据没问题。但是,如果你不关心毫秒甚至更长时间并且只希望秒值在来回转换中保持稳定,那么最简单的方法是添加epsilon值:
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;
}
这增加了整体舍入误差,但确保错误处于“安全”方向,即将其转换回time_duration
将得到相同的seconds()
值,并且可见的更改将是在milliseconds()
级别。