Skip to content

Commit

Permalink
Add examples in docs describing timezone chanegs
Browse files Browse the repository at this point in the history
  • Loading branch information
SijmenHuizenga committed Nov 13, 2023
1 parent 85fd9fc commit 34ea9bb
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 8 deletions.
28 changes: 20 additions & 8 deletions docs/timezones.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,30 @@ This causes the ``next_run`` and ``last_run`` to always be in Pythons local time

Daylight Saving Time
~~~~~~~~~~~~~~~~~~~~
When scheduling jobs with relative time (that is when not using ``.at()``), daylight saving time (DST) is **not** taken into account.
A job that is set to run every 4 hours might execute after 3 realtime hours when DST goes into effect.
This is because schedule is timezone-unaware for relative times.
Scheduling jobs that do not specify a timezone do **not** take clock-changes into account.
Timezone unaware jobs will use naive local times to calculate the next run.
For example, a job that is set to run every 4 hours might execute after 3 realtime hours when DST goes into effect.

However, when using ``.at()``, DST **is** handed correctly: the job will always run at (or close after) the set timestamp.
A job scheduled during a moment that is skipped, the job will execute after the clock is moved.
For example, a job is scheduled ``.at("02:30")``, clock moves from ``02:00`` to ``03:00``, the job will run at ``03:00``.
But when passing a timezone to ``.at()``, DST **is** taken into account.
The job will run at the specified time, even when the clock changes.

Example
Example clock moves forward:
~~~~~~~
A job is scheduled ``.at("02:30", "Europe/Berlin")``.
When the clock moves from ``02:00`` to ``03:00``, the job will run once at ``03:30``.
The day after it will return to normal and run at ``02:30``.

Example clock moves backwards:
~~~~~~~
A job is scheduled ``.at("02:30", "Europe/Berlin")``.
When the clock moves from ``02:00`` to ``03:00``, the job will run once at ``02:30``.
It will run only at the first time the clock hits ``02:30``, but not the second time.
The day after, it will return to normal and run at ``02:30``.

Example scheduling across timezones
~~~~~~~
Let's say we are in ``Europe/Berlin`` and local datetime is ``2022 march 20, 10:00:00``.
At the moment daylight saving time is not in effect in Berlin (UTC+1).
At this moment daylight saving time is not in effect in Berlin (UTC+1).

We schedule a job to run every day at 10:30:00 in America/New_York.
At this time, daylight saving time is in effect in New York (UTC-4).
Expand Down
34 changes: 34 additions & 0 deletions test_schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,40 @@ def test_at_timezone(self):
assert next.hour == 15
assert next.minute == 30

# Test the DST-case that is described in the documentation
with mock_datetime(2023, 3, 26, 1, 30):
# Current Berlin time: 01:30 (NOT during daylight saving)
# Expected to run: 02:30 - this time doesn't exist
# because clock moves from 02:00 to 03:00
# Next run: 03:30
job = every().day.at("02:30", "Europe/Berlin").do(mock_job)
assert job.next_run.day == 26
assert job.next_run.hour == 3
assert job.next_run.minute == 30
with mock_datetime(2023, 3, 27, 1, 30):
# the next day the job shall again run at 02:30
job.run()
assert job.next_run.day == 27
assert job.next_run.hour == 2
assert job.next_run.minute == 30

# Test the DST-case that is described in the documentation
with mock_datetime(2023, 10, 29, 1, 30):
# Current Berlin time: 01:30 (during daylight saving)
# Expected to run: 02:30 - this time exists twice
# because clock moves from 03:00 to 02:00
# Next run should be at the first occurrence of 02:30
job = every().day.at("02:30", "Europe/Berlin").do(mock_job)
assert job.next_run.day == 29
assert job.next_run.hour == 2
assert job.next_run.minute == 30
with mock_datetime(2023, 10, 29, 2, 35):
# After the job runs, the next run should be scheduled on the next day at 02:30
job.run()
assert job.next_run.day == 30
assert job.next_run.hour == 2
assert job.next_run.minute == 30

with mock_datetime(2022, 3, 20, 10, 0):
# Current Berlin time: 10:00 (local) (NOT during daylight saving)
# Current Krasnoyarsk time: 16:00
Expand Down

0 comments on commit 34ea9bb

Please sign in to comment.