mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-26 10:53:44 +03:00
46bf23caf4
* tests/test_dates.py: add tests for date/time typecasting and adaption. * psycopg/adapter_mxdatetime.c (mxdatetime_str): add support for outputting BC dates (which involves switching them to one-based dates). Also remove broken handling of microseconds. * psycopg/typecast.c (typecast_parse_date): if the string ends with "BC" adjust the year value to be a zero-based BC value as used by mx.DateTime (datetime doesn't support BC dates). (typecast_parse_time): ignore ' ', 'B' and 'C' in time strings rather than treating them as part of the seconds part of the time.
469 lines
17 KiB
Python
469 lines
17 KiB
Python
#!/usr/bin/env python
|
|
import math
|
|
import unittest
|
|
|
|
import psycopg2
|
|
import tests
|
|
|
|
|
|
class CommonDatetimeTestsMixin:
|
|
|
|
def execute(self, *args):
|
|
conn = psycopg2.connect("dbname=%s" % tests.dbname)
|
|
curs = conn.cursor()
|
|
curs.execute(*args)
|
|
return curs.fetchone()[0]
|
|
|
|
def test_parse_date(self):
|
|
value = self.DATE('2007-01-01', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.year, 2007)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
|
|
def test_parse_null_date(self):
|
|
value = self.DATE(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
def test_parse_time(self):
|
|
value = self.TIME('13:30:29', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.hour, 13)
|
|
self.assertEqual(value.minute, 30)
|
|
self.assertEqual(value.second, 29)
|
|
|
|
def test_parse_null_time(self):
|
|
value = self.TIME(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
def test_parse_datetime(self):
|
|
value = self.DATETIME('2007-01-01 13:30:29', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.year, 2007)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
self.assertEqual(value.hour, 13)
|
|
self.assertEqual(value.minute, 30)
|
|
self.assertEqual(value.second, 29)
|
|
|
|
def test_parse_null_datetime(self):
|
|
value = self.DATETIME(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
def test_parse_null_interval(self):
|
|
value = self.INTERVAL(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
|
|
class DatetimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
|
"""Tests for the datetime based date handling in psycopg2."""
|
|
|
|
def setUp(self):
|
|
self.DATE = psycopg2._psycopg.PYDATE
|
|
self.TIME = psycopg2._psycopg.PYTIME
|
|
self.DATETIME = psycopg2._psycopg.PYDATETIME
|
|
self.INTERVAL = psycopg2._psycopg.PYINTERVAL
|
|
|
|
def test_parse_bc_date(self):
|
|
# datetime does not support BC dates
|
|
self.assertRaises(ValueError, self.DATE, '00042-01-01 BC', None)
|
|
|
|
def test_parse_bc_datetime(self):
|
|
# datetime does not support BC dates
|
|
self.assertRaises(ValueError, self.DATETIME,
|
|
'00042-01-01 13:30:29 BC', None)
|
|
|
|
def test_parse_time_microseconds(self):
|
|
value = self.TIME('13:30:29.123456', None)
|
|
self.assertEqual(value.second, 29)
|
|
self.assertEqual(value.microsecond, 123456)
|
|
|
|
def test_parse_datetime_microseconds(self):
|
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
|
self.assertEqual(value.second, 29)
|
|
self.assertEqual(value.microsecond, 123456)
|
|
|
|
def test_parse_interval(self):
|
|
value = self.INTERVAL('42 days 12:34:56.123456', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.days, 42)
|
|
self.assertEqual(value.seconds, 45296)
|
|
self.assertEqual(value.microseconds, 123456)
|
|
|
|
def test_parse_negative_interval(self):
|
|
value = self.INTERVAL('-42 days -12:34:56.123456', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.days, -43)
|
|
self.assertEqual(value.seconds, 41103)
|
|
self.assertEqual(value.microseconds, 876544)
|
|
|
|
def test_adapt_date(self):
|
|
from datetime import date
|
|
value = self.execute('select (%s)::date::text',
|
|
[date(2007, 1, 1)])
|
|
self.assertEqual(value, '2007-01-01')
|
|
|
|
def test_adapt_time(self):
|
|
from datetime import time
|
|
value = self.execute('select (%s)::time::text',
|
|
[time(13, 30, 29)])
|
|
self.assertEqual(value, '13:30:29')
|
|
|
|
def test_adapt_datetime(self):
|
|
from datetime import datetime
|
|
value = self.execute('select (%s)::timestamp::text',
|
|
[datetime(2007, 1, 1, 13, 30, 29)])
|
|
self.assertEqual(value, '2007-01-01 13:30:29')
|
|
|
|
def test_adapt_timedelta(self):
|
|
from datetime import timedelta
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[timedelta(days=42, seconds=45296,
|
|
microseconds=123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, 3674096)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
def test_adapt_megative_timedelta(self):
|
|
from datetime import timedelta
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[timedelta(days=-42, seconds=45296,
|
|
microseconds=123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, -3583504)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
|
|
# Only run the datetime tests if psycopg was compiled with support.
|
|
if not hasattr(psycopg2._psycopg, 'PYDATETIME'):
|
|
del DatetimeTests
|
|
|
|
|
|
class mxDateTimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
|
"""Tests for the mx.DateTime based date handling in psycopg2."""
|
|
|
|
def setUp(self):
|
|
self.DATE = psycopg2._psycopg.MXDATE
|
|
self.TIME = psycopg2._psycopg.MXTIME
|
|
self.DATETIME = psycopg2._psycopg.MXDATETIME
|
|
self.INTERVAL = psycopg2._psycopg.MXINTERVAL
|
|
|
|
def test_parse_bc_date(self):
|
|
value = self.DATE('00042-01-01 BC', None)
|
|
self.assertNotEqual(value, None)
|
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
|
self.assertEqual(value.year, -41)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
|
|
def test_parse_bc_datetime(self):
|
|
value = self.DATETIME('00042-01-01 13:30:29 BC', None)
|
|
self.assertNotEqual(value, None)
|
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
|
self.assertEqual(value.year, -41)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
self.assertEqual(value.hour, 13)
|
|
self.assertEqual(value.minute, 30)
|
|
self.assertEqual(value.second, 29)
|
|
|
|
def test_parse_time_microseconds(self):
|
|
value = self.TIME('13:30:29.123456', None)
|
|
self.assertEqual(math.floor(value.second), 29)
|
|
self.assertEqual(
|
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
|
|
|
def test_parse_datetime_microseconds(self):
|
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
|
self.assertEqual(math.floor(value.second), 29)
|
|
self.assertEqual(
|
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
|
|
|
def test_parse_interval(self):
|
|
value = self.INTERVAL('42 days 05:50:05', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.day, 42)
|
|
self.assertEqual(value.hour, 5)
|
|
self.assertEqual(value.minute, 50)
|
|
self.assertEqual(value.second, 5)
|
|
|
|
def test_adapt_time(self):
|
|
from mx.DateTime import Time
|
|
value = self.execute('select (%s)::time::text',
|
|
[Time(13, 30, 29)])
|
|
self.assertEqual(value, '13:30:29')
|
|
|
|
def test_adapt_datetime(self):
|
|
from mx.DateTime import DateTime
|
|
value = self.execute('select (%s)::timestamp::text',
|
|
[DateTime(2007, 1, 1, 13, 30, 29.123456)])
|
|
self.assertEqual(value, '2007-01-01 13:30:29.123456')
|
|
|
|
def test_adapt_bc_datetime(self):
|
|
from mx.DateTime import DateTime
|
|
value = self.execute('select (%s)::timestamp::text',
|
|
[DateTime(-41, 1, 1, 13, 30, 29.123456)])
|
|
self.assertEqual(value, '0042-01-01 13:30:29.123456 BC')
|
|
|
|
def test_adapt_timedelta(self):
|
|
from mx.DateTime import DateTimeDeltaFrom
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[DateTimeDeltaFrom(days=42,
|
|
seconds=45296.123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, 3674096)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
def test_adapt_megative_timedelta(self):
|
|
from mx.DateTime import DateTimeDeltaFrom
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[DateTimeDeltaFrom(days=-42,
|
|
seconds=45296.123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, -3583504)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
|
|
# Only run the mx.DateTime tests if psycopg was compiled with support.
|
|
if not hasattr(psycopg2._psycopg, 'MXDATETIME'):
|
|
del mxDateTimeTests
|
|
|
|
|
|
def test_suite():
|
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
|
|
|
#!/usr/bin/env python
|
|
import math
|
|
import unittest
|
|
|
|
import psycopg2
|
|
import tests
|
|
|
|
|
|
class CommonDatetimeTestsMixin:
|
|
|
|
def execute(self, *args):
|
|
conn = psycopg2.connect("dbname=%s" % tests.dbname)
|
|
curs = conn.cursor()
|
|
curs.execute(*args)
|
|
return curs.fetchone()[0]
|
|
|
|
def test_parse_date(self):
|
|
value = self.DATE('2007-01-01', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.year, 2007)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
|
|
def test_parse_null_date(self):
|
|
value = self.DATE(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
def test_parse_time(self):
|
|
value = self.TIME('13:30:29', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.hour, 13)
|
|
self.assertEqual(value.minute, 30)
|
|
self.assertEqual(value.second, 29)
|
|
|
|
def test_parse_null_time(self):
|
|
value = self.TIME(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
def test_parse_datetime(self):
|
|
value = self.DATETIME('2007-01-01 13:30:29', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.year, 2007)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
self.assertEqual(value.hour, 13)
|
|
self.assertEqual(value.minute, 30)
|
|
self.assertEqual(value.second, 29)
|
|
|
|
def test_parse_null_datetime(self):
|
|
value = self.DATETIME(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
def test_parse_null_interval(self):
|
|
value = self.INTERVAL(None, None)
|
|
self.assertEqual(value, None)
|
|
|
|
|
|
class DatetimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
|
"""Tests for the datetime based date handling in psycopg2."""
|
|
|
|
def setUp(self):
|
|
self.DATE = psycopg2._psycopg.PYDATE
|
|
self.TIME = psycopg2._psycopg.PYTIME
|
|
self.DATETIME = psycopg2._psycopg.PYDATETIME
|
|
self.INTERVAL = psycopg2._psycopg.PYINTERVAL
|
|
|
|
def test_parse_bc_date(self):
|
|
# datetime does not support BC dates
|
|
self.assertRaises(ValueError, self.DATE, '00042-01-01 BC', None)
|
|
|
|
def test_parse_bc_datetime(self):
|
|
# datetime does not support BC dates
|
|
self.assertRaises(ValueError, self.DATETIME,
|
|
'00042-01-01 13:30:29 BC', None)
|
|
|
|
def test_parse_time_microseconds(self):
|
|
value = self.TIME('13:30:29.123456', None)
|
|
self.assertEqual(value.second, 29)
|
|
self.assertEqual(value.microsecond, 123456)
|
|
|
|
def test_parse_datetime_microseconds(self):
|
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
|
self.assertEqual(value.second, 29)
|
|
self.assertEqual(value.microsecond, 123456)
|
|
|
|
def test_parse_interval(self):
|
|
value = self.INTERVAL('42 days 12:34:56.123456', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.days, 42)
|
|
self.assertEqual(value.seconds, 45296)
|
|
self.assertEqual(value.microseconds, 123456)
|
|
|
|
def test_parse_negative_interval(self):
|
|
value = self.INTERVAL('-42 days -12:34:56.123456', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.days, -43)
|
|
self.assertEqual(value.seconds, 41103)
|
|
self.assertEqual(value.microseconds, 876544)
|
|
|
|
def test_adapt_date(self):
|
|
from datetime import date
|
|
value = self.execute('select (%s)::date::text',
|
|
[date(2007, 1, 1)])
|
|
self.assertEqual(value, '2007-01-01')
|
|
|
|
def test_adapt_time(self):
|
|
from datetime import time
|
|
value = self.execute('select (%s)::time::text',
|
|
[time(13, 30, 29)])
|
|
self.assertEqual(value, '13:30:29')
|
|
|
|
def test_adapt_datetime(self):
|
|
from datetime import datetime
|
|
value = self.execute('select (%s)::timestamp::text',
|
|
[datetime(2007, 1, 1, 13, 30, 29)])
|
|
self.assertEqual(value, '2007-01-01 13:30:29')
|
|
|
|
def test_adapt_timedelta(self):
|
|
from datetime import timedelta
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[timedelta(days=42, seconds=45296,
|
|
microseconds=123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, 3674096)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
def test_adapt_megative_timedelta(self):
|
|
from datetime import timedelta
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[timedelta(days=-42, seconds=45296,
|
|
microseconds=123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, -3583504)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
|
|
# Only run the datetime tests if psycopg was compiled with support.
|
|
if not hasattr(psycopg2._psycopg, 'PYDATETIME'):
|
|
del DatetimeTests
|
|
|
|
|
|
class mxDateTimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
|
"""Tests for the mx.DateTime based date handling in psycopg2."""
|
|
|
|
def setUp(self):
|
|
self.DATE = psycopg2._psycopg.MXDATE
|
|
self.TIME = psycopg2._psycopg.MXTIME
|
|
self.DATETIME = psycopg2._psycopg.MXDATETIME
|
|
self.INTERVAL = psycopg2._psycopg.MXINTERVAL
|
|
|
|
def test_parse_bc_date(self):
|
|
value = self.DATE('00042-01-01 BC', None)
|
|
self.assertNotEqual(value, None)
|
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
|
self.assertEqual(value.year, -41)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
|
|
def test_parse_bc_datetime(self):
|
|
value = self.DATETIME('00042-01-01 13:30:29 BC', None)
|
|
self.assertNotEqual(value, None)
|
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
|
self.assertEqual(value.year, -41)
|
|
self.assertEqual(value.month, 1)
|
|
self.assertEqual(value.day, 1)
|
|
self.assertEqual(value.hour, 13)
|
|
self.assertEqual(value.minute, 30)
|
|
self.assertEqual(value.second, 29)
|
|
|
|
def test_parse_time_microseconds(self):
|
|
value = self.TIME('13:30:29.123456', None)
|
|
self.assertEqual(math.floor(value.second), 29)
|
|
self.assertEqual(
|
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
|
|
|
def test_parse_datetime_microseconds(self):
|
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
|
self.assertEqual(math.floor(value.second), 29)
|
|
self.assertEqual(
|
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
|
|
|
def test_parse_interval(self):
|
|
value = self.INTERVAL('42 days 05:50:05', None)
|
|
self.assertNotEqual(value, None)
|
|
self.assertEqual(value.day, 42)
|
|
self.assertEqual(value.hour, 5)
|
|
self.assertEqual(value.minute, 50)
|
|
self.assertEqual(value.second, 5)
|
|
|
|
def test_adapt_time(self):
|
|
from mx.DateTime import Time
|
|
value = self.execute('select (%s)::time::text',
|
|
[Time(13, 30, 29)])
|
|
self.assertEqual(value, '13:30:29')
|
|
|
|
def test_adapt_datetime(self):
|
|
from mx.DateTime import DateTime
|
|
value = self.execute('select (%s)::timestamp::text',
|
|
[DateTime(2007, 1, 1, 13, 30, 29.123456)])
|
|
self.assertEqual(value, '2007-01-01 13:30:29.123456')
|
|
|
|
def test_adapt_bc_datetime(self):
|
|
from mx.DateTime import DateTime
|
|
value = self.execute('select (%s)::timestamp::text',
|
|
[DateTime(-41, 1, 1, 13, 30, 29.123456)])
|
|
self.assertEqual(value, '0042-01-01 13:30:29.123456 BC')
|
|
|
|
def test_adapt_timedelta(self):
|
|
from mx.DateTime import DateTimeDeltaFrom
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[DateTimeDeltaFrom(days=42,
|
|
seconds=45296.123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, 3674096)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
def test_adapt_megative_timedelta(self):
|
|
from mx.DateTime import DateTimeDeltaFrom
|
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
|
[DateTimeDeltaFrom(days=-42,
|
|
seconds=45296.123456)])
|
|
seconds = math.floor(value)
|
|
self.assertEqual(seconds, -3583504)
|
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
|
|
|
|
|
# Only run the mx.DateTime tests if psycopg was compiled with support.
|
|
if not hasattr(psycopg2._psycopg, 'MXDATETIME'):
|
|
del mxDateTimeTests
|
|
|
|
|
|
def test_suite():
|
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
|
|