summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--psycopg/typecast_datetime.c3
-rwxr-xr-xtests/test_dates.py26
3 files changed, 33 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 0a5de09..3437775 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,10 @@ What's new in psycopg 2.7.2
- Parse intervals returned as microseconds from Redshift (:ticket:`#558`).
- Added `~psycopg2.extras.Json` `!prepare()` method to consider connection
params when adapting (:ticket:`#562`).
+- Convert PostgreSQL :sql:`interval` containing years and months into
+ Python `~datetime.timedelta` with `!total_seconds()` matching the
+ :sql:`interval` epoch, i.e. add 6 hours every year or 12 months
+ (:ticket:`#570`).
- `~psycopg2.errorcodes` map updated to PostgreSQL 10 beta 1.
diff --git a/psycopg/typecast_datetime.c b/psycopg/typecast_datetime.c
index b0b257b..279a87d 100644
--- a/psycopg/typecast_datetime.c
+++ b/psycopg/typecast_datetime.c
@@ -448,6 +448,9 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs)
/* add the days, months years together - they already include a sign */
days += 30 * (PY_LONG_LONG)months + 365 * (PY_LONG_LONG)years;
+ /* Postgres adds 6 hours for each year, or for each 12 months */
+ seconds += 6 * 60 * 60 * (PY_LONG_LONG)(years + (months / 12));
+
return PyObject_CallFunction((PyObject*)PyDateTimeAPI->DeltaType, "LLl",
days, seconds, micros);
}
diff --git a/tests/test_dates.py b/tests/test_dates.py
index a541558..d556d78 100755
--- a/tests/test_dates.py
+++ b/tests/test_dates.py
@@ -223,6 +223,32 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
def test_parse_negative_interval(self):
self._check_interval('-42 days -12:34:56.123456')
+ def test_parse_mixied_signs_interval(self):
+ # Intervals in postgres have 4 blocks
+ # -1 year -2 mons +3 days -04:05:06
+ # each can be missing, present with no sign, positive, negative
+ # test all the combos
+ def cases(s):
+ return ['', s, '-' + s, '+' + s]
+
+ from itertools import product
+ for parts in product(
+ cases('1 year'), cases('2 months'),
+ cases('3 days'), cases('04:05:06')):
+ s = ' '.join(parts)
+ if s.isspace():
+ continue
+ self._check_interval(s)
+
+ def test_parse_interval_element(self):
+ for i in range(-1000, 1100, 100):
+ self._check_interval('%s years' % i)
+ self._check_interval('%s months' % i)
+ self._check_interval('%s days' % i)
+ self._check_interval('%s hours' % i)
+ self._check_interval('%s minutes' % i)
+ self._check_interval('%s seconds' % i)
+
def test_parse_infinity(self):
value = self.DATETIME('-infinity', self.curs)
self.assertEqual(str(value), '0001-01-01 00:00:00')