Skip to content

Commit ee86c14

Browse files
committed
Tests: Use UTC-based utcnow().date() instead of local date.today()
`datetime.date.today()` returns the current local date. So, its outcome depends on the system time zone. Because we want to use UTC-based date and time objects instead, `datetime.utcnow().date()` is a better choice.
1 parent d385118 commit ee86c14

File tree

5 files changed

+97
-3
lines changed

5 files changed

+97
-3
lines changed

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def read(path):
7070
'zope.testing>=4,<5',
7171
'zope.testrunner>=5,<6',
7272
'zc.customdoctests>=1.0.1,<2',
73+
'time-machine>=2,<3',
7374
'createcoverage>=1,<2',
7475
'stopit>=1.1.2,<2',
7576
'flake8>=4,<5'],

src/crate/client/sqlalchemy/doctests/itests.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ aren't set when the row is inserted as there is no default method::
105105

106106
The datetime and date can be set using a update statement::
107107

108-
>>> location.nullable_date = datetime.today()
108+
>>> location.nullable_date = datetime.utcnow().date()
109109
>>> location.nullable_datetime = datetime.utcnow()
110110
>>> session.flush()
111111

src/crate/client/tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import unittest
2828
import doctest
2929
from pprint import pprint
30-
from datetime import datetime, date
30+
from datetime import datetime
3131
from http.server import HTTPServer, BaseHTTPRequestHandler
3232
import ssl
3333
import time
@@ -213,7 +213,7 @@ class Location(Base):
213213
__tablename__ = 'locations'
214214
name = sa.Column(sa.String, primary_key=True)
215215
kind = sa.Column(sa.String)
216-
date = sa.Column(sa.Date, default=date.today)
216+
date = sa.Column(sa.Date, default=lambda: datetime.utcnow().date())
217217
datetime_tz = sa.Column(sa.DateTime, default=datetime.utcnow)
218218
datetime_notz = sa.Column(sa.DateTime, default=datetime.utcnow)
219219
nullable_datetime = sa.Column(sa.DateTime)

src/crate/testing/test_datetime.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# -*- coding: utf-8; -*-
2+
#
3+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
4+
# license agreements. See the NOTICE file distributed with this work for
5+
# additional information regarding copyright ownership. Crate licenses
6+
# this file to you under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License. You may
8+
# obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15+
# License for the specific language governing permissions and limitations
16+
# under the License.
17+
#
18+
# However, if you have executed another commercial license agreement
19+
# with Crate these terms will supersede the license and you may use the
20+
# software solely pursuant to the terms of the relevant commercial agreement.
21+
22+
import os
23+
import sys
24+
import unittest
25+
from datetime import datetime, date
26+
from unittest import TestCase, mock
27+
28+
import time_machine
29+
30+
31+
class DateTodayTest(TestCase):
32+
"""
33+
`date.today()` returns the current local date, as advertised in the
34+
documentation [1]. Thus, it depends on the system time zone.
35+
36+
The following test cases demonstrate that the test suite previously
37+
failed around midnight, where the UTC vs. non-UTC days overlapped,
38+
and when running on machines with non-UTC time zone.
39+
40+
On the other hand, `datetime.utcnow().date()` works equally well in all
41+
situations, so we want to use that within the SQLAlchemy test cases.
42+
43+
Funny enough, the problem is not observable on Linux?
44+
45+
[1] https://docs.python.org/3/library/datetime.html#datetime.date.today
46+
"""
47+
48+
@mock.patch.dict(os.environ, {"TZ": "UTC"})
49+
@time_machine.travel("2022-07-22T00:42:00+0200")
50+
def test_date_today_depends_on_system_timezone_success_on_utc(self):
51+
today_local = date.today()
52+
today_utc = datetime.utcnow().date()
53+
self.assertEqual(today_local, today_utc)
54+
self.assertEqual(today_local, date(2022, 7, 21))
55+
self.assertEqual(today_utc, date(2022, 7, 21))
56+
57+
@unittest.skipIf(sys.platform == "linux", "Problem not observable on Linux")
58+
@mock.patch.dict(os.environ, {"TZ": "Europe/Prague"})
59+
@time_machine.travel("2022-07-22T00:42:00+0200")
60+
def test_date_today_depends_on_system_timezone_failure_on_non_utc(self):
61+
today_local = date.today()
62+
today_utc = datetime.utcnow().date()
63+
self.assertNotEqual(today_local, today_utc)
64+
self.assertEqual(today_local, date(2022, 7, 22))
65+
self.assertEqual(today_utc, date(2022, 7, 21))
66+
67+
@mock.patch.dict(os.environ, {"TZ": "UTC"})
68+
@time_machine.travel("2022-07-22T00:42:00+0200")
69+
def test_date_today_utc(self):
70+
today_local = date.today()
71+
self.assertEqual(today_local, date(2022, 7, 21))
72+
73+
@unittest.skipIf(sys.platform == "linux", "Problem not observable on Linux")
74+
@mock.patch.dict(os.environ, {"TZ": "Europe/Prague"})
75+
@time_machine.travel("2022-07-22T00:42:00+0200")
76+
def test_date_today_non_utc(self):
77+
today_local = date.today()
78+
self.assertEqual(today_local, date(2022, 7, 22))
79+
80+
@mock.patch.dict(os.environ, {"TZ": "UTC"})
81+
@time_machine.travel("2022-07-22T00:42:00+0200")
82+
def test_utcnow_date_utc(self):
83+
today_utc = datetime.utcnow().date()
84+
self.assertEqual(today_utc, date(2022, 7, 21))
85+
86+
@mock.patch.dict(os.environ, {"TZ": "Europe/Prague"})
87+
@time_machine.travel("2022-07-22T00:42:00+0200")
88+
def test_utcnow_date_non_utc(self):
89+
today_utc = datetime.utcnow().date()
90+
self.assertEqual(today_utc, date(2022, 7, 21))

src/crate/testing/tests.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import unittest
2525
import doctest
2626
import tempfile
27+
28+
from .test_datetime import DateTodayTest
2729
from .test_layer import LayerUtilsTest
2830

2931

@@ -64,4 +66,5 @@ def test_suite():
6466
)
6567
suite.addTest(s)
6668
suite.addTest(unittest.makeSuite(LayerUtilsTest))
69+
suite.addTest(unittest.makeSuite(DateTodayTest))
6770
return suite

0 commit comments

Comments
 (0)