From 6ddfd1e090de6b5f1d1a14f7c51790275bff5818 Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Thu, 25 Aug 2016 19:59:41 +1000 Subject: [PATCH] Add in casts for c++11s chrono classes to pythons datetime --- include/pybind11/cast.h | 109 ++++++++++++++++++++++++++++++++++++++ include/pybind11/common.h | 1 + 2 files changed, 110 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index b885298a..4a0c703a 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -472,6 +472,115 @@ public: PYBIND11_TYPE_CASTER(bool, _("bool")); }; +template class type_caster> { +public: + typedef std::chrono::duration type; + typedef std::chrono::duration> days; + + bool load(handle src, bool) { + using namespace std::chrono; + PyDateTime_IMPORT; + + if (!src) return false; + if (PyDelta_Check(src.ptr())) { + const PyDateTime_Delta* delta = reinterpret_cast(src.ptr()); + value = duration_cast>( + days(delta->days) + + seconds(delta->seconds) + + microseconds(delta->microseconds)); + return true; + } + else return false; + } + + static handle cast(const std::chrono::duration &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + PyDateTime_IMPORT; + + int dd = duration_cast(src).count(); + int ss = duration_cast(src % days(1)).count(); + int us = duration_cast(src % seconds(1)).count(); + + return PyDelta_FromDSU(dd, ss, us); + } + PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); +}; + +template class type_caster> { +public: + typedef std::chrono::time_point type; + bool load(handle src, bool) { + using namespace std::chrono; + PyDateTime_IMPORT; + + if (!src) return false; + if (PyDateTime_Check(src.ptr())) { + std::tm cal; + cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); + cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); + cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); + cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); + cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; + cal.tm_year = PyDateTime_GET_YEAR(src.ptr()); + cal.tm_isdst = -1; + + value = system_clock::from_time_t(mktime(&cal)); + return true; + } + else return false; + } + + static handle cast(const std::chrono::time_point &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + PyDateTime_IMPORT; + + time_t tt = system_clock::to_time_t(src); + tm *ltime = localtime(&tt); // this function uses static memory so it's best + tm localtime = *ltime; // to copy it out asap just in case + + return PyDateTime_FromDateAndTime(localtime.tm_year, localtime.tm_mon + 1 + , localtime.tm_mday + , localtime.tm_hour + , localtime.tm_min + , localtime.tm_sec + , (duration_cast(src.time_since_epoch()) % seconds(1)).count()); + } + PYBIND11_TYPE_CASTER(type, _("datetime.datetime")); +}; + +template class type_caster> { +public: + typedef std::chrono::time_point type; + bool load(handle src, bool) { + using namespace std::chrono; + PyDateTime_IMPORT; + + if (!src) return false; + if (PyTime_Check(src.ptr())) { + value = type(duration_cast( + hours(PyDateTime_TIME_GET_HOUR(src.ptr())) + + minutes(PyDateTime_TIME_GET_MINUTE(src.ptr())) + + seconds(PyDateTime_TIME_GET_SECOND(src.ptr())) + + microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr())) + )); + return true; + } + else return false; + } + + static handle cast(const std::chrono::time_point &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + PyDateTime_IMPORT; + + Duration d = src.time_since_epoch(); + return PyTime_FromTime(duration_cast(d).count() + , duration_cast(d % hours(1)).count() + , duration_cast(d % minutes(1)).count() + , duration_cast(d % seconds(1)).count()); + } + PYBIND11_TYPE_CASTER(type, _("datetime.time")); +}; + template <> class type_caster { public: bool load(handle src, bool) { diff --git a/include/pybind11/common.h b/include/pybind11/common.h index fd65fe76..c1287daf 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -46,6 +46,7 @@ #endif #include +#include #include #include