From 541904b6c281ff3f59b0c61fd1de878d57cb89b0 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Fri, 17 Jul 2026 18:15:52 -0700 Subject: [PATCH] fix: use DAYS_PER_YEAR (365) for whole years in interval-to-timedelta conversion PyQueryResult::convertValueToPyObject (pybind path) and all interval conversion sites in _lbug_capi.py (C-API path) now use days = years * 365 + months * 30 + days instead of days = months * 30 + days This gives 365 days per whole year instead of 360, matching the engine's Interval::DAYS_PER_YEAR constant. --- src_cpp/py_query_result.cpp | 7 ++++++- src_py/_lbug_capi.py | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src_cpp/py_query_result.cpp b/src_cpp/py_query_result.cpp index 080180c..d76df30 100644 --- a/src_cpp/py_query_result.cpp +++ b/src_cpp/py_query_result.cpp @@ -235,7 +235,12 @@ py::object PyQueryResult::convertValueToPyObject(const Value& value) { } case LogicalTypeID::INTERVAL: { auto intervalVal = value.getValue(); - auto days = Interval::DAYS_PER_MONTH * intervalVal.months + intervalVal.days; + // Use DAYS_PER_YEAR for whole years instead of DAYS_PER_MONTH * 12, + // giving 365 days/year + 30 days/month for the remainder. + auto years = intervalVal.months / Interval::MONTHS_PER_YEAR; + auto months = intervalVal.months % Interval::MONTHS_PER_YEAR; + auto days = years * Interval::DAYS_PER_YEAR + months * Interval::DAYS_PER_MONTH + + intervalVal.days; return py::cast(importCache->datetime.timedelta()(py::arg("days") = days, py::arg("microseconds") = intervalVal.micros)); diff --git a/src_py/_lbug_capi.py b/src_py/_lbug_capi.py index f4d6eef..332249d 100644 --- a/src_py/_lbug_capi.py +++ b/src_py/_lbug_capi.py @@ -1853,7 +1853,11 @@ def _convert_value(self, value: _LbugValue) -> Any: ), "Failed to read interval", ) - total_days = int(out.days) + int(out.months) * 30 + total_days = ( + int(out.days) + + (int(out.months) // 12) * 365 + + (int(out.months) % 12) * 30 + ) return dt.timedelta(days=total_days, microseconds=int(out.micros)) if type_id in (_LBUG_LIST, _LBUG_ARRAY): size = ctypes.c_uint64(0) @@ -1937,7 +1941,8 @@ def _convert_value(self, value: _LbugValue) -> Any: ): total_days = ( int(interval_probe.days) - + int(interval_probe.months) * 30 + + (int(interval_probe.months) // 12) * 365 + + (int(interval_probe.months) % 12) * 30 ) out_obj[key] = dt.timedelta( days=total_days, @@ -2042,7 +2047,8 @@ def _convert_value(self, value: _LbugValue) -> Any: ): total_days = ( int(interval_probe.days) - + int(interval_probe.months) * 30 + + (int(interval_probe.months) // 12) * 365 + + (int(interval_probe.months) % 12) * 30 ) out_obj[key] = dt.timedelta( days=total_days, @@ -2095,7 +2101,9 @@ def _convert_value(self, value: _LbugValue) -> Any: == _LBUG_SUCCESS ): total_days = ( - int(interval_probe.days) + int(interval_probe.months) * 30 + int(interval_probe.days) + + (int(interval_probe.months) // 12) * 365 + + (int(interval_probe.months) % 12) * 30 ) return dt.timedelta( days=total_days, microseconds=int(interval_probe.micros)