#include <boost/python.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <datetime.h> // compile with -I/path/to/python/include
/**
* Convert boost::posix_ptime objects (ptime and time_duration)
* to/from python datetime objects (datetime and timedelta).
*
* Credits:
* http://libtorrent.svn.sourceforge.net/viewvc/libtorrent/trunk/bindings/python/src/datetime.cpp
* http://www.nabble.com/boost::posix_time::ptime-conversion-td16857866.html
*/
static long get_usecs(boost::posix_time::time_duration const& d)
{
static long resolution
= boost::posix_time::time_duration::ticks_per_second();
long fracsecs = d.fractional_seconds();
if (resolution > 1000000)
return fracsecs / (resolution / 1000000);
else
return fracsecs * (1000000 / resolution);
}
/* Convert ptime to/from python */
struct ptime_to_python_datetime
{
static PyObject* convert(boost::posix_time::ptime const& pt)
{
boost::gregorian::date date = pt.date();
boost::posix_time::time_duration td = pt.time_of_day();
return PyDateTime_FromDateAndTime((int)date.year(),
(int)date.month(),
(int)date.day(),
td.hours(),
td.minutes(),
td.seconds(),
get_usecs(td));
}
};
struct ptime_from_python_datetime
{
ptime_from_python_datetime()
{
boost::python::converter::registry::push_back(
&convertible,
&construct,
boost::python::type_id<boost::posix_time::ptime > ());
}
static void* convertible(PyObject * obj_ptr)
{
if ( ! PyDateTime_Check(obj_ptr))
return 0;
return obj_ptr;
}
static void construct(
PyObject* obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data * data)
{
PyDateTime_DateTime const* pydate
= reinterpret_cast<PyDateTime_DateTime*>(obj_ptr);
// Create date object
boost::gregorian::date _date(PyDateTime_GET_YEAR(pydate),
PyDateTime_GET_MONTH(pydate),
PyDateTime_GET_DAY(pydate));
// Create time duration object
boost::posix_time::time_duration
_duration(PyDateTime_DATE_GET_HOUR(pydate),
PyDateTime_DATE_GET_MINUTE(pydate),
PyDateTime_DATE_GET_SECOND(pydate),
0);
// Set the usecs value
_duration += boost::posix_time::microseconds(PyDateTime_DATE_GET_MICROSECOND(pydate));
// Create posix time object
void* storage = (
(boost::python::converter::rvalue_from_python_storage<boost::posix_time::ptime>*)
data)->storage.bytes;
new (storage)
boost::posix_time::ptime(_date, _duration);
data->convertible = storage;
}
};
/* Convert time_duration to/from python */
struct tduration_to_python_delta
{
static PyObject* convert(boost::posix_time::time_duration d)
{
long days = d.hours() / 24;
if (days < 0)
days --;
long seconds = d.total_seconds() - days*(24*3600);
long usecs = get_usecs(d);
if (days < 0)
usecs = 1000000-1 - usecs;
return PyDelta_FromDSU(days, seconds, usecs);
}
};
/* Should support the negative values, but not the special boost time
durations */
struct tduration_from_python_delta
{
tduration_from_python_delta()
{
boost::python::converter::registry::push_back(
&convertible,
&construct,
boost::python::type_id<boost::posix_time::time_duration>());
}
static void* convertible(PyObject * obj_ptr)
{
if ( ! PyDelta_Check(obj_ptr))
return 0;
return obj_ptr;
}
static void construct(
PyObject* obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data * data)
{
PyDateTime_Delta const* pydelta
= reinterpret_cast<PyDateTime_Delta*>(obj_ptr);
long days = pydelta->days;
bool is_negative = (days < 0);
if (is_negative)
days = -days;
// Create time duration object
boost::posix_time::time_duration
duration = boost::posix_time::hours(24)*days
+ boost::posix_time::seconds(pydelta->seconds)
+ boost::posix_time::microseconds(pydelta->microseconds);
if (is_negative)
duration = duration.invert_sign();
void* storage = (
(boost::python::converter::rvalue_from_python_storage<boost::posix_time::time_duration>*)
data)->storage.bytes;
new (storage)
boost::posix_time::time_duration(duration);
data->convertible = storage;
}
};
void bind_datetime()
{
PyDateTime_IMPORT;
ptime_from_python_datetime();
to_python_converter<
const boost::posix_time::ptime
, ptime_to_python_datetime
>();
tduration_from_python_delta();
to_python_converter<
const boost::posix_time::time_duration
, tduration_to_python_delta
>();
}