Skip to content

Commit 6b48443

Browse files
committed
Make interval decoding logic match that of psycopg2.
asyncpg will now treat 12-month interval increments as 365-day spans, instead of 12*30 day spans. This matches psycopg2 interval decoding logic. Fixes: #150.
1 parent 1b1893d commit 6b48443

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

asyncpg/protocol/codecs/datetime.pyx

+10-2
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,23 @@ cdef interval_decode(ConnectionSettings settings, FastReadBuffer buf):
248248
cdef:
249249
int32_t days
250250
int32_t months
251+
int32_t years
251252
int64_t seconds = 0
252253
uint32_t microseconds = 0
253254

254255
_decode_time(buf, &seconds, &microseconds)
255256
days = hton.unpack_int32(buf.read(4))
256257
months = hton.unpack_int32(buf.read(4))
257258

258-
return datetime.timedelta(days=days + months * 30, seconds=seconds,
259-
microseconds=microseconds)
259+
if months < 0:
260+
years = -<int32_t>(-months // 12)
261+
months = -<int32_t>(-months % 12)
262+
else:
263+
years = <int32_t>(months // 12)
264+
months = <int32_t>(months % 12)
265+
266+
return datetime.timedelta(days=days + months * 30 + years * 365,
267+
seconds=seconds, microseconds=microseconds)
260268

261269

262270
cdef init_datetime_codecs():

tests/test_codecs.py

+13
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,19 @@ def test_bitstring(self):
439439

440440
self.assertEqual(len(bits.bytes), expected_bytelen)
441441

442+
async def test_interval(self):
443+
res = await self.con.fetchval("SELECT '5 years'::interval")
444+
self.assertEqual(res, datetime.timedelta(days=1825))
445+
446+
res = await self.con.fetchval("SELECT '5 years 1 month'::interval")
447+
self.assertEqual(res, datetime.timedelta(days=1855))
448+
449+
res = await self.con.fetchval("SELECT '-5 years'::interval")
450+
self.assertEqual(res, datetime.timedelta(days=-1825))
451+
452+
res = await self.con.fetchval("SELECT '-5 years -1 month'::interval")
453+
self.assertEqual(res, datetime.timedelta(days=-1855))
454+
442455
async def test_unhandled_type_fallback(self):
443456
await self.con.execute('''
444457
CREATE EXTENSION IF NOT EXISTS isn

0 commit comments

Comments
 (0)