【问题标题】:Swig pass Python datetime object to C++Swig 将 Python 日期时间对象传递给 C++
【发布时间】:2022-09-24 19:32:20
【问题描述】:

我在 C++ 中有一个函数,它从纪元开始以纳秒的形式传递 uint64_t。我已将此数字包装在对象 DateTime 中,如

struct DateTime {
    uint64_t epochns;
};
void print( DateTime ts );

显然,该函数不完全是print,因为我可以为此目的使用 Python 自己的。

重要的是我将它与 Python 日期时间对象无缝地使用,如

print( datetime(1985,7,1) )

我不确定如何编写满足此要求的类型图。

有什么提示吗?

    标签: python swig cpython


    【解决方案1】:

    在对象上调用方法datetime.timestamp 以秒为单位返回纪元,然后乘以1E6 得到微秒并舍入为整数。然后再乘以 1000 得到纳秒。

    %typemap(in)  DateTime
    {
        PyObject* str = PyString_FromString( "timestamp" );
        PyObject* obj = PyObject_CallMethodObjArgs( $input, str, nullptr );
        $1.epochns = int64_t(PyFloat_AsDouble( obj )*1000000)*1000LL;
        Py_XDECREF( obj );
        Py_XDECREF( str );
    }
    

    中间乘法是必要的,就像你直接乘以 1E9 一样,你将在纳秒部分有未舍入的垃圾。

    2022 年 9 月 24 日更新我最终得到了这个扩展代码,它也需要日期时间、时间和时间增量。此外,上面的代码会将所有内容都作为本地时区,这是我不想要的。我希望时间都在UTC,没有时区干预。

    在我的痛饮文件中:

    %typemap(in)  hb::DateTime
    {
        $1.epochns = hb::getEpochNanos( $input );
    }
    

    在我的 C++ 源代码中的某处:

    int64_t getEpochNanos(PyObject* obj) {
        if (PyDateTime_CheckExact(obj) || PyDate_CheckExact(obj)) {
            int64_t usecs = PyDateTime_DATE_GET_MICROSECOND(obj);
            struct tm tms;
            memset(&tms, 0, sizeof(tms));
            tms.tm_wday = -1;
            tms.tm_year = PyDateTime_GET_YEAR(obj) - 1900;
            tms.tm_mon = PyDateTime_GET_MONTH(obj) - 1;
            tms.tm_mday = PyDateTime_GET_DAY(obj);
            tms.tm_hour = PyDateTime_DATE_GET_HOUR(obj);
            tms.tm_min = PyDateTime_DATE_GET_MINUTE(obj);
            tms.tm_sec = PyDateTime_DATE_GET_SECOND(obj);
            time_t tt = timegm(&tms);
            if (tms.tm_wday == -1) return 0;
            return int64_t(tt) * 1000000000LL + usecs * 1000;
        } else if (PyTime_Check(obj)) {
            int64_t usecs = PyDateTime_TIME_GET_MICROSECOND(obj);
            int64_t hour = PyDateTime_TIME_GET_HOUR(obj);
            int64_t min = PyDateTime_TIME_GET_MINUTE(obj);
            int64_t sec = PyDateTime_TIME_GET_SECOND(obj);
            return int64_t(((hour * 60) + min) * 60 + sec) * 1000000000LL + usecs * 1000;
        } else if (PyDelta_Check(obj)) {
            int64_t usecs = PyDateTime_DELTA_GET_MICROSECONDS(obj);
            int64_t days = PyDateTime_DELTA_GET_DAYS(obj);
            int64_t sec = PyDateTime_DELTA_GET_SECONDS(obj);
            return int64_t(days * 86400 + sec) * 1000000000LL + usecs * 1000;
        }
        return -1;
    }
    

    请注意,我将-1 设置为 wday 中的哨兵。事实上,-1 是一个有效的纪元(纪元前 1 天),因此检查调用是否失败的唯一方法是将 wday 设置为负一,然后再检查。如果调用成功,wday 将相应地设置为工作日(0 到 6),但如果失败则不会。

    【讨论】:

    • 您可以使用PyObject_CallMethod($input, "timestamp", nullptr) 并节省几行。不要忘记检查obj 是否为NULL,以防传递了非日期时间对象。
    • @MarkTolonen 谢谢!
    猜你喜欢
    • 2021-11-03
    • 2018-07-29
    • 2018-12-06
    • 2018-11-09
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    相关资源
    最近更新 更多