|
Boost : |
Subject: [boost] OLE Automation date to local_date_time conversion
From: Matthew Chambers (matthew.chambers_at_[hidden])
Date: 2009-06-24 12:36:10
Hello fellow boosters,
Under MSVC boost::date_time supports conversion from FILETIME, so it
makes sense to also support conversion from the OLE automation date
format, helpfully defined at:
http://msdn.microsoft.com/en-us/library/system.datetime.fromoadate.aspx
> The d parameter is a double-precision floating-point number that
> represents a date as the number of days before or after the base date,
> midnight, 30 December 1899. The sign and integral part of d encode the
> date as a positive or negative day displacement from 30 December 1899,
> and the absolute value of the fractional part of d encodes the time of
> day as a fraction of a day displacement from midnight. d must be a
> value between negative 657435.0 through positive 2958466.0.
In fact, I don't see a good reason this function can't be included in a
non-MSVC build too since it doesn't depend on the Win32 API in any way.
The code to handle this conversion is quite ugly. Here is my code to do it:
namespace boost {
namespace date_time {
//! Create a time object from an OLE automation date value.
/*! Create a time object from an OLE automation date value.
* The oa_date parameter is a double-precision floating-point number that
* represents a date as the number of days before or after the base
date, midnight,
* 30 December 1899. The sign and integral part of oa_date encode the
date as a
* positive or negative day displacement from 30 December 1899, and the
absolute
* value of the fractional part of oa_date encodes the time of day as a
fraction of a
* day displacement from midnight. oa_date must be a value between
* negative 657435.0 through positive 2958466.0.
*/
template<class time_type>
inline
time_type time_from_OADATE(double oa_date)
{
typedef typename time_type::date_type date_type;
typedef typename time_type::date_duration_type date_duration_type;
typedef typename time_type::time_duration_type time_duration_type;
using boost::math::modf;
static const date_type base_date(1899, Dec, 30);
static const time_type base_time(base_date, time_duration_type(0,0,0));
int dayOffset, hourOffset, minuteOffset, secondOffset;
double fraction = fabs(modf(oa_date, &dayOffset)) * 24; // fraction
= hours
fraction = modf(fraction, &hourOffset) * 60; // fraction = minutes
fraction = modf(fraction, &minuteOffset) * 60; // fraction = seconds
modf(fraction, &secondOffset);
time_type t(base_time);
t += time_duration_type(hourOffset, minuteOffset, secondOffset);
t += date_duration_type(dayOffset);
return t;
}
}
}
Here are some basic unit tests:
template<typename time_type>
void test_time_from_OADATE(std::ostream* os_ = NULL)
{
typedef typename time_type::date_type date_type;
typedef typename time_type::date_duration_type date_duration_type;
typedef typename time_type::time_duration_type time_duration_type;
using namespace boost::date_time;
if (os_) *os_ << "OADATE: 0.0 -> " <<
time_from_OADATE<time_type>(0.0) << endl;
unit_assert(time_from_OADATE<time_type>(0.0) ==
time_type(date_type(1899, Dec, 30), time_duration_type(0,0,0)));
if (os_) *os_ << "OADATE: 1.0 -> " <<
time_from_OADATE<time_type>(1.0) << endl;
unit_assert(time_from_OADATE<time_type>(1.0) ==
time_type(date_type(1899, Dec, 31), time_duration_type(0,0,0)));
if (os_) *os_ << "OADATE: -1.0 -> " <<
time_from_OADATE<time_type>(-1.0) << endl;
unit_assert(time_from_OADATE<time_type>(-1.0) ==
time_type(date_type(1899, Dec, 29), time_duration_type(0,0,0)));
if (os_) *os_ << "OADATE: 2.0 -> " <<
time_from_OADATE<time_type>(2.0) << endl;
unit_assert(time_from_OADATE<time_type>(2.0) ==
time_type(date_type(1900, Jan, 1), time_duration_type(0,0,0)));
if (os_) *os_ << "OADATE: 2.25 -> " <<
time_from_OADATE<time_type>(2.25) << endl;
unit_assert(time_from_OADATE<time_type>(2.25) ==
time_type(date_type(1900, Jan, 1), time_duration_type(6,0,0)));
if (os_) *os_ << "OADATE: -1.25 -> " <<
time_from_OADATE<time_type>(-1.25) << endl;
unit_assert(time_from_OADATE<time_type>(-1.25) ==
time_type(date_type(1899, Dec, 29), time_duration_type(6,0,0)));
}
I made it templated because its sibling function in
boost\date_time\filetime_functions.hpp is templated, but it seems that
ptime is the only stock type that will work. Local_time doesn't have the
right constructors, at least.
Thoughts? What's the procedure to add this officially to date_time?
Thanks,
-Matt Chambers
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk