Welcome, guest | Sign In | My Account | Store | Cart
#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
    >();
}

History

  • revision 10 (15 years ago)
  • previous revisions are not available