diff options
author | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2021-06-14 23:46:39 +0100 |
---|---|---|
committer | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2021-06-15 00:17:14 +0100 |
commit | f28502663f1c318dd01c975cf70e3dcce544ab3b (patch) | |
tree | 1bf52dee88b416407560a43783758d58e76d23e0 | |
parent | 2eac70786e7034888e43a316f05a39e6063253b6 (diff) | |
download | psycopg2-f28502663f1c318dd01c975cf70e3dcce544ab3b.tar.gz |
Use datetime.timezone as default tzinfo_factory.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | doc/src/cursor.rst | 6 | ||||
-rw-r--r-- | doc/src/usage.rst | 16 | ||||
-rw-r--r-- | psycopg/cursor_type.c | 7 | ||||
-rw-r--r-- | psycopg/typecast_datetime.c | 13 | ||||
-rwxr-xr-x | tests/test_dates.py | 18 |
6 files changed, 47 insertions, 15 deletions
@@ -20,6 +20,8 @@ Other changes: - Dropped support for Python 2.7, 3.4, 3.5 (:tickets:`#1198, #1000, #1197`). - Dropped support for mx.DateTime. +- Use `datetime.timezone` objects by default in datetime objects instead of + `~psycopg2.tz.FixedOffsetTimezone`. - Build system for Linux/MacOS binary packages moved to GitHub action, now providing :pep:`600`\-style wheels packages. diff --git a/doc/src/cursor.rst b/doc/src/cursor.rst index 8398c98..2123b17 100644 --- a/doc/src/cursor.rst +++ b/doc/src/cursor.rst @@ -498,8 +498,10 @@ The ``cursor`` class The time zone factory used to handle data types such as :sql:`TIMESTAMP WITH TIME ZONE`. It should be a `~datetime.tzinfo` - object. A few implementations are available in the `psycopg2.tz` - module. + object. Default is `datetime.timezone`. + + .. versionchanged:: 2.9 + previosly the default factory was `psycopg2.tz.FixedOffsetTimezone`. .. method:: nextset() diff --git a/doc/src/usage.rst b/doc/src/usage.rst index b4ffc85..5bb69e9 100644 --- a/doc/src/usage.rst +++ b/doc/src/usage.rst @@ -574,14 +574,13 @@ Time zones handling ''''''''''''''''''' The PostgreSQL type :sql:`timestamp with time zone` (a.k.a. -:sql:`timestamptz`) is converted into Python `~datetime.datetime` objects with -a `~datetime.datetime.tzinfo` attribute set to a -`~psycopg2.tz.FixedOffsetTimezone` instance. +:sql:`timestamptz`) is converted into Python `~datetime.datetime` objects. >>> cur.execute("SET TIME ZONE 'Europe/Rome'") # UTC + 1 hour >>> cur.execute("SELECT '2010-01-01 10:30:45'::timestamptz") - >>> cur.fetchone()[0].tzinfo - psycopg2.tz.FixedOffsetTimezone(offset=60, name=None) + >>> cur.fetchone()[0] + datetime.datetime(2010, 1, 1, 10, 30, 45, + tzinfo=datetime.timezone(datetime.timedelta(seconds=3600))) .. note:: @@ -594,9 +593,9 @@ a `~datetime.datetime.tzinfo` attribute set to a >>> cur.execute("SELECT '1900-01-01 10:30:45'::timestamptz") >>> cur.fetchone()[0].tzinfo # On Python 3.6: 5h, 21m - psycopg2.tz.FixedOffsetTimezone(offset=datetime.timedelta(0, 19260), name=None) + datetime.timezone(datetime.timedelta(0, 19260)) # On Python 3.7 and following: 5h, 21m, 10s - psycopg2.tz.FixedOffsetTimezone(offset=datetime.timedelta(seconds=19270), name=None) + datetime.timezone(datetime.timedelta(seconds=19270)) .. versionchanged:: 2.2.2 timezones with seconds are supported (with rounding). Previously such @@ -605,6 +604,9 @@ a `~datetime.datetime.tzinfo` attribute set to a .. versionchanged:: 2.9 timezones with seconds are supported without rounding. +.. versionchanged:: 2.9 + use `datetime.timezone` as default tzinfo object instead of + `~psycopg2.tz.FixedOffsetTimezone`. .. index:: double: Date objects; Infinite diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 31ce792..abab40c 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -1951,10 +1951,11 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name) /* default tzinfo factory */ { + /* The datetime api doesn't seem to have a constructor to make a + * datetime.timezone, so use the Python interface. */ PyObject *m = NULL; - if ((m = PyImport_ImportModule("psycopg2.tz"))) { - self->tzinfo_factory = PyObject_GetAttrString( - m, "FixedOffsetTimezone"); + if ((m = PyImport_ImportModule("datetime"))) { + self->tzinfo_factory = PyObject_GetAttrString(m, "timezone"); Py_DECREF(m); } if (!self->tzinfo_factory) { diff --git a/psycopg/typecast_datetime.c b/psycopg/typecast_datetime.c index d700069..121a228 100644 --- a/psycopg/typecast_datetime.c +++ b/psycopg/typecast_datetime.c @@ -104,9 +104,18 @@ _parse_inftz(const char *str, PyObject *curs) goto exit; } - if (!(tzinfo = PyObject_CallFunction(tzinfo_factory, "i", 0))) { - goto exit; +#if PY_VERSION_HEX < 0x03070000 + { + PyObject *tzoff; + if (!(tzoff = PyDelta_FromDSU(0, 0, 0))) { goto exit; } + tzinfo = PyObject_CallFunctionObjArgs(tzinfo_factory, tzoff, NULL); + Py_DECREF(tzoff); + if (!tzinfo) { goto exit; } } +#else + tzinfo = PyDateTime_TimeZone_UTC; + Py_INCREF(tzinfo); +#endif /* m.replace(tzinfo=tzinfo) */ if (!(args = PyTuple_New(0))) { goto exit; } diff --git a/tests/test_dates.py b/tests/test_dates.py index 728bb57..850c991 100755 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -26,7 +26,7 @@ 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 @@ -192,6 +192,22 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin): 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) |