19
19
IntervalError ,
20
20
)
21
21
22
+ # POSIX TZ string format
23
+ TZ_BERLIN = "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"
24
+ TZ_AUCKLAND = "NZST-12NZDT-13,M10.1.0/02:00:00,M3.3.0/03:00:00"
25
+ TZ_UTC = "UTC0"
26
+
22
27
# Set timezone to Europe/Berlin (CEST) to ensure global reproducibility
23
- os .environ ["TZ" ] = "CET-1CEST,M3.5.0,M10.5.0"
28
+ os .environ ["TZ" ] = TZ_BERLIN
24
29
time .tzset ()
25
30
26
31
@@ -35,14 +40,16 @@ class mock_datetime:
35
40
Monkey-patch datetime for predictable results
36
41
"""
37
42
38
- def __init__ (self , year , month , day , hour , minute , second = 0 ):
43
+ def __init__ (self , year , month , day , hour , minute , second = 0 , zone = None ):
39
44
self .year = year
40
45
self .month = month
41
46
self .day = day
42
47
self .hour = hour
43
48
self .minute = minute
44
49
self .second = second
50
+ self .zone = zone
45
51
self .original_datetime = None
52
+ self .original_zone = None
46
53
47
54
def __enter__ (self ):
48
55
class MockDate (datetime .datetime ):
@@ -64,12 +71,20 @@ def now(cls):
64
71
self .original_datetime = datetime .datetime
65
72
datetime .datetime = MockDate
66
73
74
+ self .original_zone = os .environ .get ("TZ" )
75
+ if self .zone :
76
+ os .environ ["TZ" ] = self .zone
77
+ time .tzset ()
78
+
67
79
return MockDate (
68
80
self .year , self .month , self .day , self .hour , self .minute , self .second
69
81
)
70
82
71
83
def __exit__ (self , * args , ** kwargs ):
72
84
datetime .datetime = self .original_datetime
85
+ if self .original_zone :
86
+ os .environ ["TZ" ] = self .original_zone
87
+ time .tzset ()
73
88
74
89
75
90
class SchedulerTests (unittest .TestCase ):
@@ -583,6 +598,36 @@ def test_at_timezone(self):
583
598
)
584
599
assert schedule .idle_seconds () == expected_delta .total_seconds ()
585
600
601
+ with mock_datetime (2023 , 9 , 18 , 10 , 59 , 0 , TZ_AUCKLAND ):
602
+ # Testing issue #598
603
+ # Current Auckland time: 10:59 (local) (NOT during daylight saving)
604
+ # Current UTC time: 21:59 (17 september)
605
+ # Expected to run UTC time: sept-18 00:00
606
+ # Next run Auckland time: sept-18 12:00
607
+ schedule .clear ()
608
+ next = every ().day .at ("00:00" , "UTC" ).do (mock_job ).next_run
609
+ assert next .day == 18
610
+ assert next .hour == 12
611
+ assert next .minute == 0
612
+
613
+ # Test that .day.at() and .monday.at() are equivalent in this case
614
+ schedule .clear ()
615
+ next = every ().monday .at ("00:00" , "UTC" ).do (mock_job ).next_run
616
+ assert next .day == 18
617
+ assert next .hour == 12
618
+ assert next .minute == 0
619
+
620
+ with mock_datetime (2023 , 7 , 15 , 13 , 0 , 0 , TZ_UTC ):
621
+ # Testing issue #592
622
+ # Current UTC time: 13:00
623
+ # Expected to run US East time: 9:45 (daylight saving active)
624
+ # Next run UTC time: july-15 13:45
625
+ schedule .clear ()
626
+ next = every ().day .at ("09:45" , "US/Eastern" ).do (mock_job ).next_run
627
+ assert next .day == 15
628
+ assert next .hour == 13
629
+ assert next .minute == 45
630
+
586
631
with self .assertRaises (pytz .exceptions .UnknownTimeZoneError ):
587
632
every ().day .at ("10:30" , "FakeZone" ).do (mock_job )
588
633
0 commit comments