Skip to content

Commit 13da63b

Browse files
committed
Timestamp values: Remove the use of "naive" Python datetime objects
Python: Remove invocations to deprecated `datetime.utcfromtimestamp()`. This is a possible BREAKING CHANGE about returned Python ``datetime`` objects: > Removed the use of "naive" Python ``datetime`` objects, i.e. instances without ``tzinfo`` attribute set. When no ``time_zone`` information is specified when creating a database connection or cursor, ``datetime`` objects will now use Coordinated Universal Time (UTC), like CrateDB is storing timestamp values in this format. This update is coming from a deprecation of Python's ``datetime.utcfromtimestamp()``, which is effectively also phasing out the use of "naive" timestamp objects in Python, in favor of using timezone-aware objects, also to represent datetimes in UTC. It may be a breaking change for some users of the library that don't expect to receive "aware" ``datetime`` objects from now on. DeprecationWarning: datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.fromtimestamp(timestamp, datetime.UTC).
1 parent b9800a9 commit 13da63b

File tree

7 files changed

+44
-16
lines changed

7 files changed

+44
-16
lines changed

CHANGES.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ Unreleased
88
- The SQLAlchemy dialect has been split off into the `sqlalchemy-cratedb`_
99
package. See `Migrate from crate.client to sqlalchemy-cratedb`_ to learn
1010
about necessary migration steps.
11+
- Returned Python ``datetime`` objects are now always timezone-aware,
12+
using UTC by default. This is a possible BREAKING CHANGE: Removed the use
13+
of "naive" Python ``datetime`` objects, i.e. instances without ``tzinfo``
14+
attribute set.
15+
When no ``time_zone`` information is specified when creating a database
16+
connection or cursor, ``datetime`` objects will now use Coordinated
17+
Universal Time (UTC), like CrateDB is storing timestamp values in this
18+
format.
19+
This update is coming from a deprecation of Python's
20+
``datetime.utcfromtimestamp()``, which is effectively also phasing out
21+
the use of "naive" timestamp objects in Python, in favor of using
22+
timezone-aware objects, also to represent datetimes in UTC. It may be a
23+
breaking change for some users of the library that don't expect to
24+
receive "aware" ``datetime`` objects from now on.
1125
- Configured DB API interface attribute ``threadsafety = 1``, which signals
1226
"Threads may share the module, but not connections."
1327
- Added ``error_trace`` to string representation of an Error to relay

docs/by-example/cursor.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ types. Currently, this is implemented for the CrateDB data types ``IP`` and
333333
>>> cursor.execute('')
334334

335335
>>> cursor.fetchone()
336-
['foo', IPv4Address('10.10.10.1'), datetime.datetime(2022, 7, 18, 18, 10, 36, 758000)]
336+
['foo', IPv4Address('10.10.10.1'), datetime.datetime(2022, 7, 18, 18, 10, 36, 758000, tzinfo=datetime.timezone.utc)]
337337

338338

339339
Custom data type conversion
@@ -374,8 +374,7 @@ Proof that the converter works correctly, ``B\'0110\'`` should be converted to
374374
=======================================
375375

376376
Based on the data type converter functionality, the driver offers a convenient
377-
interface to make it return timezone-aware ``datetime`` objects, using the
378-
desired time zone.
377+
interface to make it return ``datetime`` objects using the desired time zone.
379378

380379
For your reference, in the following examples, epoch 1658167836758 is
381380
``Mon, 18 Jul 2022 18:10:36 GMT``.

docs/query.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,7 @@ converter function defined as ``lambda``, which assigns ``yes`` for boolean
244244
=======================================
245245

246246
Based on the data type converter functionality, the driver offers a convenient
247-
interface to make it return timezone-aware ``datetime`` objects, using the
248-
desired time zone.
247+
interface to make it return ``datetime`` objects using the desired time zone.
249248

250249
For your reference, in the following examples, epoch 1658167836758 is
251250
``Mon, 18 Jul 2022 18:10:36 GMT``.

src/crate/client/connection.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,15 @@ def __init__(
119119
- ``zoneinfo.ZoneInfo("Australia/Sydney")``
120120
- ``+0530`` (UTC offset in string format)
121121
122+
The driver always returns timezone-"aware" `datetime` objects,
123+
with their `tzinfo` attribute set.
124+
122125
When `time_zone` is `None`, the returned `datetime` objects are
123-
"naive", without any `tzinfo`, converted using ``datetime.utcfromtimestamp(...)``.
126+
using Coordinated Universal Time (UTC), because CrateDB is storing
127+
timestamp values in this format.
124128
125-
When `time_zone` is given, the returned `datetime` objects are "aware",
126-
with `tzinfo` set, converted using ``datetime.fromtimestamp(..., tz=...)``.
129+
When `time_zone` is given, the timestamp values will be transparently
130+
converted from UTC to use the given time zone.
127131
""" # noqa: E501
128132

129133
self._converter = converter

src/crate/client/converter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
https://crate.io/docs/crate/reference/en/latest/interfaces/http.html#column-types
2525
"""
2626

27+
import datetime as dt
2728
import ipaddress
2829
from copy import deepcopy
29-
from datetime import datetime
3030
from enum import Enum
3131
from typing import Any, Callable, Dict, List, Optional, Union
3232

@@ -45,13 +45,13 @@ def _to_ipaddress(
4545
return ipaddress.ip_address(value)
4646

4747

48-
def _to_datetime(value: Optional[float]) -> Optional[datetime]:
48+
def _to_datetime(value: Optional[float]) -> Optional[dt.datetime]:
4949
"""
5050
https://docs.python.org/3/library/datetime.html
5151
"""
5252
if value is None:
5353
return None
54-
return datetime.utcfromtimestamp(value / 1e3)
54+
return dt.datetime.fromtimestamp(value / 1e3, tz=dt.timezone.utc)
5555

5656

5757
def _to_default(value: Optional[Any]) -> Optional[Any]:

src/crate/client/cursor.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,15 @@ def time_zone(self, tz):
258258
- ``zoneinfo.ZoneInfo("Australia/Sydney")``
259259
- ``+0530`` (UTC offset in string format)
260260
261+
The driver always returns timezone-"aware" `datetime` objects,
262+
with their `tzinfo` attribute set.
263+
261264
When `time_zone` is `None`, the returned `datetime` objects are
262-
"naive", without any `tzinfo`, converted using
263-
`datetime.utcfromtimestamp(...)`.
265+
using Coordinated Universal Time (UTC), because CrateDB is storing
266+
timestamp values in this format.
264267
265-
When `time_zone` is given, the returned `datetime` objects are "aware",
266-
with `tzinfo` set, converted by `datetime.fromtimestamp(..., tz=...)`.
268+
When `time_zone` is given, the timestamp values will be transparently
269+
converted from UTC to use the given time zone.
267270
"""
268271

269272
# Do nothing when time zone is reset.

tests/client/test_cursor.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,16 @@ def test_execute_with_converter(self):
205205
[
206206
"foo",
207207
IPv4Address("10.10.10.1"),
208-
datetime.datetime(2022, 7, 18, 18, 10, 36, 758000),
208+
datetime.datetime(
209+
2022,
210+
7,
211+
18,
212+
18,
213+
10,
214+
36,
215+
758000,
216+
tzinfo=datetime.timezone.utc,
217+
),
209218
6,
210219
],
211220
[None, None, None, None],

0 commit comments

Comments
 (0)