Skip to content

Commit baca0dc

Browse files
hicham-amazighelkorchi
authored andcommitted
[GR-68973] Backport to 25.0: Github issue #532: datetime.strptime is broken with timezones without DST
PullRequest: graalpython/4000
2 parents a7be968 + 6f54c07 commit baca0dc

File tree

5 files changed

+55
-21
lines changed

5 files changed

+55
-21
lines changed

.github/workflows/downstream-tests.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jobs:
1313
- pybind11
1414
- virtualenv
1515
- pyo3
16+
- jiter
1617
os:
1718
- id: ubuntu-latest
1819
platform: linux
@@ -35,7 +36,7 @@ jobs:
3536
run: brew install cmake
3637

3738
- name: Install Rust toolchain
38-
if: ${{ matrix.name == 'pyo3' }}
39+
if: ${{ matrix.name == 'pyo3' || matrix.name == 'jiter' }}
3940
run: |
4041
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
4142
echo "${HOME}/.cargo/bin" >> $GITHUB_PATH

ci.jsonnet

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@
493493
) + [
494494
{
495495
name: "graalpy-website-build",
496-
targets: ["gate"],
496+
targets: ["tier1"],
497497
guard: {
498498
includes: ["docs/user/**", "docs/site/**"],
499499
},

graalpython/com.oracle.graal.python.test/src/tests/test_time.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -36,10 +36,14 @@
3636
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
39-
40-
import time
4139
import calendar
40+
import os
41+
import subprocess
42+
import sys
43+
import time
4244
import unittest
45+
from textwrap import dedent
46+
4347

4448
def test_sleep():
4549
start = time.time()
@@ -72,19 +76,19 @@ def test_new_struct_time(self):
7276
self.assertEqual(t.tm_mday, 26)
7377
self.assertEqual(t[2], 26)
7478
self.assertEqual(t.tm_zone, None)
75-
79+
7680
self.assertRaises(TypeError, time.struct_time, (2018, 11, 26, 17, 34, 12, 0, 340))
7781
self.assertRaises(TypeError, time.struct_time, (2018, 11, 26, 17, 34, 12, 0, 340, 9, 10, 11, 12))
7882

7983
def test_from_times(self):
8084
gt = time.gmtime()
8185
self.assertNotEqual(gt.tm_zone, None)
8286
self.assertNotEqual(gt.tm_gmtoff, None)
83-
87+
8488
lt = time.localtime()
8589
self.assertNotEqual(lt.tm_zone, None)
8690
self.assertNotEqual(lt.tm_gmtoff, None)
87-
91+
8892
def test_destructuring_assignment(self):
8993
t = time.struct_time((1,2,3,4,5,6,7,8,9))
9094
y,m,d,h,mi,s,wd,yd,dst = t
@@ -93,7 +97,7 @@ def test_destructuring_assignment(self):
9397
self.assertEqual(dst, 9)
9498
self.assertEqual(t.tm_zone, None)
9599
self.assertEqual(t.tm_gmtoff, None)
96-
100+
97101
t = time.struct_time((11,12,13,14,15,16,17,18,19,20, 21))
98102
y,m,d,h,mi,s,wd,yd,dst = t
99103
self.assertEqual(y, 11)
@@ -234,7 +238,7 @@ def test_Yeary(self):
234238
self.check_format("%y", (2018, 11, 28, 10, 0, 0, -1, 1, 0), '18')
235239
self.check_format("%y", (18, 11, 28, 10, 0, 0, 0, 1, 0), '18')
236240
self.check_format("%y", (0, 11, 25, 11, 12, 2, 3, 1, 0), '00')
237-
# This is failing on CPython, which return '35'
241+
# This is failing on CPython, which return '35'
238242
#self.check_format("%y", (-365, 11, 24, 23, 20, 61, 6, 1, 0), '65')
239243
self.check_format("%y", (17829, 11, 24, 23, 20, 61, 7, 1, 0), '29')
240244

@@ -280,3 +284,28 @@ def test_padding(self):
280284
self.check_format("%Y-%b-%d-%j", (2018, 8, 8, 15, 24, 10, 3, 55, 0), '2018-Aug-08-055')
281285
self.check_format("%Y-%b-%-d-%-j", (2018, 8, 8, 15, 24, 10, 3, 5, 0), '2018-Aug-8-5')
282286
self.check_format("%Y-%b-%-d-%-j", (2018, 8, 8, 15, 24, 10, 3, 55, 0), '2018-Aug-8-55')
287+
288+
@unittest.skipIf(sys.platform == 'win32', "Cannot change timezone per-process on Windows")
289+
def test_default_tz_dst_no_dst(self):
290+
env = os.environ.copy()
291+
testdate = '1994-11-15 12:45:26'
292+
for tz, expected in [
293+
('UTC', f"tzname=('UTC', 'UTC'), timezone=0, altzone=0, daylight=0, testdate={testdate}"),
294+
('Europe/Prague', f"tzname=('CET', 'CEST'), timezone=-3600, altzone=-7200, daylight=1, testdate={testdate}"),
295+
('Australia/Sydney', f"tzname=('AEST', 'AEDT'), timezone=-36000, altzone=-39600, daylight=1, testdate={testdate}"),
296+
]:
297+
env['TZ'] = tz
298+
env['LC_ALL'] = 'C'
299+
script = dedent('''\
300+
from time import *
301+
from datetime import datetime
302+
# Regression test for issue #532
303+
testdate = datetime.strptime('Tue, 15 Nov 1994 12:45:26 GMT', '%a, %d %b %Y %H:%M:%S %Z')
304+
print(f'{tzname=}, {timezone=}, {altzone=}, {daylight=}, {testdate=!s}')
305+
''')
306+
out = subprocess.check_output(
307+
[sys.executable, '-c', script],
308+
env=env,
309+
text=True,
310+
).strip()
311+
self.assertEqual(expected, out)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,10 @@ public void postInitialize(Python3Core core) {
174174
TruffleString noDaylightSavingZone = toTruffleStringUncached(defaultTimeZone.getDisplayName(false, TimeZone.SHORT));
175175
TruffleString daylightSavingZone = toTruffleStringUncached(defaultTimeZone.getDisplayName(true, TimeZone.SHORT));
176176

177-
boolean hasDaylightSaving = !noDaylightSavingZone.equalsUncached(daylightSavingZone, TS_ENCODING);
178-
if (hasDaylightSaving) {
179-
timeModule.setAttribute(T_TZNAME, PFactory.createTuple(core.getLanguage(), new Object[]{noDaylightSavingZone, daylightSavingZone}));
180-
} else {
181-
timeModule.setAttribute(T_TZNAME, PFactory.createTuple(core.getLanguage(), new Object[]{noDaylightSavingZone}));
182-
}
183-
184-
timeModule.setAttribute(T_DAYLIGHT, PInt.intValue(hasDaylightSaving));
185-
int rawOffsetSeconds = defaultTimeZone.getRawOffset() / -1000;
186-
timeModule.setAttribute(T_TIMEZONE, rawOffsetSeconds);
187-
timeModule.setAttribute(T_ALTZONE, rawOffsetSeconds - 3600);
177+
timeModule.setAttribute(T_TZNAME, PFactory.createTuple(core.getLanguage(), new Object[]{noDaylightSavingZone, daylightSavingZone}));
178+
timeModule.setAttribute(T_DAYLIGHT, PInt.intValue(defaultTimeZone.getDSTSavings() != 0));
179+
timeModule.setAttribute(T_TIMEZONE, defaultTimeZone.getRawOffset() / -1000);
180+
timeModule.setAttribute(T_ALTZONE, (defaultTimeZone.getRawOffset() + defaultTimeZone.getDSTSavings()) / -1000);
188181

189182
// register_interop_behavior() for time.struct_time
190183
AbstractImportNode.importModule(T_POLYGLOT_TIME);

mx.graalpython/downstream_tests.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,17 @@ def downstream_test_pyo3(graalpy):
153153
run_in_venv(venv, ['pip', 'install', 'nox'])
154154
run_in_venv(venv, ['nox', '-s', 'test-py'], cwd=src)
155155

156+
@downstream_test('jiter')
157+
def downstream_test_jiter(graalpy, testdir):
158+
run(['git', 'clone', 'https://github.com/pydantic/jiter.git', '-b', 'main'], cwd=testdir)
159+
src = testdir / 'jiter'
160+
venv = src / 'venv'
161+
run([graalpy, '-m', 'venv', str(venv)])
162+
run_in_venv(venv, ['pip', 'install', '-r', 'crates/jiter-python/tests/requirements.txt'], cwd=src)
163+
run_in_venv(venv, ['pip', 'install', '-e', 'crates/jiter-python',
164+
'--config-settings=build-args=--profile dev'], cwd=src)
165+
run_in_venv(venv, ['pytest', '-v', '--tb=short', 'crates/jiter-python/tests'], cwd=src)
166+
run_in_venv(venv, ['python', 'crates/jiter-python/bench.py', 'jiter', 'jiter-cache', '--fast'], cwd=src)
156167

157168
def run_downstream_test(python, project):
158169
DOWNSTREAM_TESTS[project](python)

0 commit comments

Comments
 (0)