Skip to content

Commit 6f54c07

Browse files
msimacekhicham-amazigh
authored andcommitted
Fix setting time.tzname when the timezone has no DST
Fixed #532 (cherry picked from commit 3b13d07)
1 parent 85d2e82 commit 6f54c07

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

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);

0 commit comments

Comments
 (0)