summaryrefslogtreecommitdiff
path: root/tests/test_dates.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_dates.py')
-rwxr-xr-xtests/test_dates.py286
1 files changed, 82 insertions, 204 deletions
diff --git a/tests/test_dates.py b/tests/test_dates.py
index 29c37b0..d4d2e7f 100755
--- a/tests/test_dates.py
+++ b/tests/test_dates.py
@@ -23,21 +23,16 @@
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
+import sys
import math
import pickle
-from datetime import date, datetime, time, timedelta
+from datetime import date, datetime, time, timedelta, timezone
import psycopg2
from psycopg2.tz import FixedOffsetTimezone, ZERO
import unittest
from .testutils import ConnectingTestCase, skip_before_postgres, skip_if_crdb
-try:
- from mx.DateTime import Date, Time, DateTime, DateTimeDeltaFrom
-except ImportError:
- # Tests will be skipped
- pass
-
def total_seconds(d):
"""Return total number of seconds of a timedelta as a float."""
@@ -157,17 +152,27 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
self.check_time_tz("-01", -3600)
self.check_time_tz("+01:15", 4500)
self.check_time_tz("-01:15", -4500)
- # The Python datetime module does not support time zone
- # offsets that are not a whole number of minutes.
- # We round the offset to the nearest minute.
- self.check_time_tz("+01:15:00", 60 * (60 + 15))
- self.check_time_tz("+01:15:29", 60 * (60 + 15))
- self.check_time_tz("+01:15:30", 60 * (60 + 16))
- self.check_time_tz("+01:15:59", 60 * (60 + 16))
- self.check_time_tz("-01:15:00", -60 * (60 + 15))
- self.check_time_tz("-01:15:29", -60 * (60 + 15))
- self.check_time_tz("-01:15:30", -60 * (60 + 16))
- self.check_time_tz("-01:15:59", -60 * (60 + 16))
+ if sys.version_info < (3, 7):
+ # The Python < 3.7 datetime module does not support time zone
+ # offsets that are not a whole number of minutes.
+ # We round the offset to the nearest minute.
+ self.check_time_tz("+01:15:00", 60 * (60 + 15))
+ self.check_time_tz("+01:15:29", 60 * (60 + 15))
+ self.check_time_tz("+01:15:30", 60 * (60 + 16))
+ self.check_time_tz("+01:15:59", 60 * (60 + 16))
+ self.check_time_tz("-01:15:00", -60 * (60 + 15))
+ self.check_time_tz("-01:15:29", -60 * (60 + 15))
+ self.check_time_tz("-01:15:30", -60 * (60 + 16))
+ self.check_time_tz("-01:15:59", -60 * (60 + 16))
+ else:
+ self.check_time_tz("+01:15:00", 60 * (60 + 15))
+ self.check_time_tz("+01:15:29", 60 * (60 + 15) + 29)
+ self.check_time_tz("+01:15:30", 60 * (60 + 15) + 30)
+ self.check_time_tz("+01:15:59", 60 * (60 + 15) + 59)
+ self.check_time_tz("-01:15:00", -(60 * (60 + 15)))
+ self.check_time_tz("-01:15:29", -(60 * (60 + 15) + 29))
+ self.check_time_tz("-01:15:30", -(60 * (60 + 15) + 30))
+ self.check_time_tz("-01:15:59", -(60 * (60 + 15) + 59))
def check_datetime_tz(self, str_offset, offset):
base = datetime(2007, 1, 1, 13, 30, 29)
@@ -183,26 +188,52 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
self.assertEqual(value.replace(tzinfo=None), base)
# Conversion to UTC produces the expected offset.
- UTC = FixedOffsetTimezone(0, "UTC")
+ UTC = timezone(timedelta(0))
value_utc = value.astimezone(UTC).replace(tzinfo=None)
self.assertEqual(base - value_utc, timedelta(seconds=offset))
+ def test_default_tzinfo(self):
+ self.curs.execute("select '2000-01-01 00:00+02:00'::timestamptz")
+ dt = self.curs.fetchone()[0]
+ self.assert_(isinstance(dt.tzinfo, timezone))
+ self.assertEqual(dt,
+ datetime(2000, 1, 1, tzinfo=timezone(timedelta(minutes=120))))
+
+ def test_fotz_tzinfo(self):
+ self.curs.tzinfo_factory = FixedOffsetTimezone
+ self.curs.execute("select '2000-01-01 00:00+02:00'::timestamptz")
+ dt = self.curs.fetchone()[0]
+ self.assert_(not isinstance(dt.tzinfo, timezone))
+ self.assert_(isinstance(dt.tzinfo, FixedOffsetTimezone))
+ self.assertEqual(dt,
+ datetime(2000, 1, 1, tzinfo=timezone(timedelta(minutes=120))))
+
def test_parse_datetime_timezone(self):
self.check_datetime_tz("+01", 3600)
self.check_datetime_tz("-01", -3600)
self.check_datetime_tz("+01:15", 4500)
self.check_datetime_tz("-01:15", -4500)
- # The Python datetime module does not support time zone
- # offsets that are not a whole number of minutes.
- # We round the offset to the nearest minute.
- self.check_datetime_tz("+01:15:00", 60 * (60 + 15))
- self.check_datetime_tz("+01:15:29", 60 * (60 + 15))
- self.check_datetime_tz("+01:15:30", 60 * (60 + 16))
- self.check_datetime_tz("+01:15:59", 60 * (60 + 16))
- self.check_datetime_tz("-01:15:00", -60 * (60 + 15))
- self.check_datetime_tz("-01:15:29", -60 * (60 + 15))
- self.check_datetime_tz("-01:15:30", -60 * (60 + 16))
- self.check_datetime_tz("-01:15:59", -60 * (60 + 16))
+ if sys.version_info < (3, 7):
+ # The Python < 3.7 datetime module does not support time zone
+ # offsets that are not a whole number of minutes.
+ # We round the offset to the nearest minute.
+ self.check_datetime_tz("+01:15:00", 60 * (60 + 15))
+ self.check_datetime_tz("+01:15:29", 60 * (60 + 15))
+ self.check_datetime_tz("+01:15:30", 60 * (60 + 16))
+ self.check_datetime_tz("+01:15:59", 60 * (60 + 16))
+ self.check_datetime_tz("-01:15:00", -60 * (60 + 15))
+ self.check_datetime_tz("-01:15:29", -60 * (60 + 15))
+ self.check_datetime_tz("-01:15:30", -60 * (60 + 16))
+ self.check_datetime_tz("-01:15:59", -60 * (60 + 16))
+ else:
+ self.check_datetime_tz("+01:15:00", 60 * (60 + 15))
+ self.check_datetime_tz("+01:15:29", 60 * (60 + 15) + 29)
+ self.check_datetime_tz("+01:15:30", 60 * (60 + 15) + 30)
+ self.check_datetime_tz("+01:15:59", 60 * (60 + 15) + 59)
+ self.check_datetime_tz("-01:15:00", -(60 * (60 + 15)))
+ self.check_datetime_tz("-01:15:29", -(60 * (60 + 15) + 29))
+ self.check_datetime_tz("-01:15:30", -(60 * (60 + 15) + 30))
+ self.check_datetime_tz("-01:15:59", -(60 * (60 + 15) + 59))
def test_parse_time_no_timezone(self):
self.assertEqual(self.TIME("13:30:29", self.curs).tzinfo, None)
@@ -286,7 +317,7 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
self.assertEqual(None, dt.tzinfo)
def test_type_roundtrip_datetimetz(self):
- tz = FixedOffsetTimezone(8 * 60)
+ tz = timezone(timedelta(minutes=8 * 60))
dt1 = datetime(2010, 5, 3, 10, 20, 30, tzinfo=tz)
dt2 = self._test_type_roundtrip(dt1)
self.assertNotEqual(None, dt2.tzinfo)
@@ -297,7 +328,7 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
self.assertEqual(None, tm.tzinfo)
def test_type_roundtrip_timetz(self):
- tz = FixedOffsetTimezone(8 * 60)
+ tz = timezone(timedelta(minutes=8 * 60))
tm1 = time(10, 20, 30, tzinfo=tz)
tm2 = self._test_type_roundtrip(tm1)
self.assertNotEqual(None, tm2.tzinfo)
@@ -314,7 +345,7 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
def test_type_roundtrip_datetimetz_array(self):
self._test_type_roundtrip_array(
- datetime(2010, 5, 3, 10, 20, 30, tzinfo=FixedOffsetTimezone(0)))
+ datetime(2010, 5, 3, 10, 20, 30, tzinfo=timezone(timedelta(0))))
def test_type_roundtrip_time_array(self):
self._test_type_roundtrip_array(time(10, 20, 30))
@@ -328,10 +359,10 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
self.assertEqual(t, time(0, 0))
t = self.execute("select '24:00+05'::timetz;")
- self.assertEqual(t, time(0, 0, tzinfo=FixedOffsetTimezone(300)))
+ self.assertEqual(t, time(0, 0, tzinfo=timezone(timedelta(minutes=300))))
t = self.execute("select '24:00+05:30'::timetz;")
- self.assertEqual(t, time(0, 0, tzinfo=FixedOffsetTimezone(330)))
+ self.assertEqual(t, time(0, 0, tzinfo=timezone(timedelta(minutes=330))))
@skip_before_postgres(8, 1)
def test_large_interval(self):
@@ -399,11 +430,11 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
t = self.execute("select 'infinity'::timestamptz")
self.assert_(t.tzinfo is not None)
- self.assert_(t > datetime(4000, 1, 1, tzinfo=FixedOffsetTimezone()))
+ self.assert_(t > datetime(4000, 1, 1, tzinfo=timezone(timedelta(0))))
t = self.execute("select '-infinity'::timestamptz")
self.assert_(t.tzinfo is not None)
- self.assert_(t < datetime(1000, 1, 1, tzinfo=FixedOffsetTimezone()))
+ self.assert_(t < datetime(1000, 1, 1, tzinfo=timezone(timedelta(0))))
def test_redshift_day(self):
# Redshift is reported returning 1 day interval as microsec (bug #558)
@@ -435,169 +466,6 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
self.assertRaises(psycopg2.NotSupportedError, cur.fetchone)
-@unittest.skipUnless(
- hasattr(psycopg2._psycopg, 'MXDATETIME'),
- 'Requires mx.DateTime support'
-)
-class mxDateTimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
- """Tests for the mx.DateTime based date handling in psycopg2."""
-
- def setUp(self):
- ConnectingTestCase.setUp(self)
- self.curs = self.conn.cursor()
- self.DATE = psycopg2._psycopg.MXDATE
- self.TIME = psycopg2._psycopg.MXTIME
- self.DATETIME = psycopg2._psycopg.MXDATETIME
- self.INTERVAL = psycopg2._psycopg.MXINTERVAL
-
- psycopg2.extensions.register_type(self.DATE, self.conn)
- psycopg2.extensions.register_type(self.TIME, self.conn)
- psycopg2.extensions.register_type(self.DATETIME, self.conn)
- psycopg2.extensions.register_type(self.INTERVAL, self.conn)
- psycopg2.extensions.register_type(psycopg2.extensions.MXDATEARRAY, self.conn)
- psycopg2.extensions.register_type(psycopg2.extensions.MXTIMEARRAY, self.conn)
- psycopg2.extensions.register_type(
- psycopg2.extensions.MXDATETIMEARRAY, self.conn)
- psycopg2.extensions.register_type(
- psycopg2.extensions.MXINTERVALARRAY, self.conn)
-
- def tearDown(self):
- self.conn.close()
-
- def test_parse_bc_date(self):
- value = self.DATE('00042-01-01 BC', self.curs)
- self.assert_(value is not 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', self.curs)
- self.assert_(value is not 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', self.curs)
- 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', self.curs)
- self.assertEqual(math.floor(value.second), 29)
- self.assertEqual(
- int((value.second - math.floor(value.second)) * 1000000), 123456)
-
- def test_parse_time_timezone(self):
- # Time zone information is ignored.
- expected = Time(13, 30, 29)
- self.assertEqual(expected, self.TIME("13:30:29+01", self.curs))
- self.assertEqual(expected, self.TIME("13:30:29-01", self.curs))
- self.assertEqual(expected, self.TIME("13:30:29+01:15", self.curs))
- self.assertEqual(expected, self.TIME("13:30:29-01:15", self.curs))
- self.assertEqual(expected, self.TIME("13:30:29+01:15:42", self.curs))
- self.assertEqual(expected, self.TIME("13:30:29-01:15:42", self.curs))
-
- def test_parse_datetime_timezone(self):
- # Time zone information is ignored.
- expected = DateTime(2007, 1, 1, 13, 30, 29)
- self.assertEqual(
- expected, self.DATETIME("2007-01-01 13:30:29+01", self.curs))
- self.assertEqual(
- expected, self.DATETIME("2007-01-01 13:30:29-01", self.curs))
- self.assertEqual(
- expected, self.DATETIME("2007-01-01 13:30:29+01:15", self.curs))
- self.assertEqual(
- expected, self.DATETIME("2007-01-01 13:30:29-01:15", self.curs))
- self.assertEqual(
- expected, self.DATETIME("2007-01-01 13:30:29+01:15:42", self.curs))
- self.assertEqual(
- expected, self.DATETIME("2007-01-01 13:30:29-01:15:42", self.curs))
-
- def test_parse_interval(self):
- value = self.INTERVAL('42 days 05:50:05', self.curs)
- self.assert_(value is not 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):
- value = self.execute('select (%s)::time::text',
- [Time(13, 30, 29)])
- self.assertEqual(value, '13:30:29')
-
- def test_adapt_datetime(self):
- 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):
- value = self.execute('select (%s)::timestamp::text',
- [DateTime(-41, 1, 1, 13, 30, 29.123456)])
- # microsecs for BC timestamps look not available in PG < 8.4
- # but more likely it's determined at compile time.
- self.assert_(value in (
- '0042-01-01 13:30:29.123456 BC',
- '0042-01-01 13:30:29 BC'), value)
-
- def test_adapt_timedelta(self):
- 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_negative_timedelta(self):
- 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)
-
- def _test_type_roundtrip(self, o1):
- o2 = self.execute("select %s;", (o1,))
- self.assertEqual(type(o1), type(o2))
-
- def _test_type_roundtrip_array(self, o1):
- o1 = [o1]
- o2 = self.execute("select %s;", (o1,))
- self.assertEqual(type(o1[0]), type(o2[0]))
-
- def test_type_roundtrip_date(self):
- self._test_type_roundtrip(Date(2010, 5, 3))
-
- def test_type_roundtrip_datetime(self):
- self._test_type_roundtrip(DateTime(2010, 5, 3, 10, 20, 30))
-
- def test_type_roundtrip_time(self):
- self._test_type_roundtrip(Time(10, 20, 30))
-
- def test_type_roundtrip_interval(self):
- self._test_type_roundtrip(DateTimeDeltaFrom(seconds=30))
-
- def test_type_roundtrip_date_array(self):
- self._test_type_roundtrip_array(Date(2010, 5, 3))
-
- def test_type_roundtrip_datetime_array(self):
- self._test_type_roundtrip_array(DateTime(2010, 5, 3, 10, 20, 30))
-
- def test_type_roundtrip_time_array(self):
- self._test_type_roundtrip_array(Time(10, 20, 30))
-
- def test_type_roundtrip_interval_array(self):
- self._test_type_roundtrip_array(DateTimeDeltaFrom(seconds=30))
-
-
class FromTicksTestCase(unittest.TestCase):
# bug "TimestampFromTicks() throws ValueError (2-2.0.14)"
# reported by Jozsef Szalay on 2010-05-06
@@ -605,7 +473,7 @@ class FromTicksTestCase(unittest.TestCase):
s = psycopg2.TimestampFromTicks(1273173119.99992)
self.assertEqual(s.adapted,
datetime(2010, 5, 6, 14, 11, 59, 999920,
- tzinfo=FixedOffsetTimezone(-5 * 60)))
+ tzinfo=timezone(timedelta(minutes=-5 * 60))))
def test_date_value_error_sec_59_99(self):
s = psycopg2.DateFromTicks(1273173119.99992)
@@ -628,17 +496,27 @@ class FixedOffsetTimezoneTests(unittest.TestCase):
def test_repr_with_positive_offset(self):
tzinfo = FixedOffsetTimezone(5 * 60)
self.assertEqual(repr(tzinfo),
- "psycopg2.tz.FixedOffsetTimezone(offset=300, name=None)")
+ "psycopg2.tz.FixedOffsetTimezone(offset=%r, name=None)"
+ % timedelta(minutes=5 * 60))
def test_repr_with_negative_offset(self):
tzinfo = FixedOffsetTimezone(-5 * 60)
self.assertEqual(repr(tzinfo),
- "psycopg2.tz.FixedOffsetTimezone(offset=-300, name=None)")
+ "psycopg2.tz.FixedOffsetTimezone(offset=%r, name=None)"
+ % timedelta(minutes=-5 * 60))
+
+ def test_init_with_timedelta(self):
+ td = timedelta(minutes=5 * 60)
+ tzinfo = FixedOffsetTimezone(td)
+ self.assertEqual(tzinfo, FixedOffsetTimezone(5 * 60))
+ self.assertEqual(repr(tzinfo),
+ "psycopg2.tz.FixedOffsetTimezone(offset=%r, name=None)" % td)
def test_repr_with_name(self):
tzinfo = FixedOffsetTimezone(name="FOO")
self.assertEqual(repr(tzinfo),
- "psycopg2.tz.FixedOffsetTimezone(offset=0, name='FOO')")
+ "psycopg2.tz.FixedOffsetTimezone(offset=%r, name='FOO')"
+ % timedelta(0))
def test_instance_caching(self):
self.assert_(FixedOffsetTimezone(name="FOO")