如何在Python C API中实现时间加减运算?
如何在Python C API中实现时间加减运算?
我太懂这种感受了——网上一搜Python日期运算全是上层代码,C API相关的资料少得可怜。不过别担心,针对你这个需求,我来帮你把代码补全,并且把关键步骤讲清楚:
首先你已经完成了把输入的finishO转换为PyDate对象的部分,这部分逻辑是对的。接下来处理startO未指定的情况,要得到finish前一天的日期,你已经创建了代表1天的PyDelta对象,接下来只需要用Python C API的数值减法接口来完成日期和时间增量的运算,同时还要注意引用计数管理(这可是C API里的经典坑点)。
补全后的完整代码片段如下:
/* Attempt converting the finish-date, if not a date already */ if (!PyDate_Check(finishO)) { PyObject *o = PyDate_FromTimestamp(finishO); if (o == NULL) { return PyErr_Format(PyExc_ValueError, "%R is not a valid date", finishO); } // 注意:如果finishO是函数传入的借用引用,替换时无需DECREF原对象; // 若为自行创建的拥有引用的对象,记得先DECREF再替换 finishO = o; } /* If start-date is not specified, assume one day prior the finish date */ if (startO == NULL) { // 创建代表1天的时间增量对象(days, seconds, microseconds) PyObject *oneDay = PyDelta_FromDSU(1, 0, 0); if (oneDay == NULL) { // 处理创建失败的情况,比如内存不足 return NULL; } // 用日期减去1天的增量,得到前一天的日期 startO = PyNumber_Subtract(finishO, oneDay); // 释放oneDay的引用,避免内存泄漏 Py_DECREF(oneDay); // 检查运算是否成功 if (startO == NULL) { return PyErr_Format(PyExc_ValueError, "Failed to calculate previous day"); } }
我来给你划几个重点:
PyNumber_Subtract是Python C API中通用的减法接口,它支持PyDate和PyDelta之间的运算,和你在Python代码里写finish - timedelta(days=1)是完全等价的。- 引用计数一定要盯紧:
PyDelta_FromDSU创建的oneDay对象带有一个新的引用,用完之后必须调用Py_DECREF释放,否则会造成内存泄漏。 - 每一步都要检查返回值是否为
NULL,C API里容错性很低,哪怕是看似不会出错的日期运算,也得做好错误处理。
另外,还有一种更直接的方式,如果你只需要加减天数的话,可以用PyDate_AddDays函数,它接受一个PyDate对象和一个整数天数(负数就是往前减),代码会更简洁:
if (startO == NULL) { // 直接给日期加-1天,得到前一天的日期 startO = PyDate_AddDays((PyDateObject *)finishO, -1); if (startO == NULL) { return PyErr_Format(PyExc_ValueError, "Failed to calculate previous day"); } }
这种方式不需要创建PyDelta对象,少了一个引用计数管理的步骤,效率也更高,特别适合这种只加减天数的场景。
内容来源于stack exchange




