dbader / schedule

Python job scheduling for humans.
https://schedule.readthedocs.io/
MIT License
11.62k stars 954 forks source link

still having cross-timezone problems in 1.2.1 #605

Closed bellt closed 2 months ago

bellt commented 8 months ago

Hi There, It looks like 1.2.1 hasn't completely fixed the bug highlighted in #579 . Using a combination of their example code and your tests, I've come up with the following which demonstrates the problem:

import schedule
import datetime
import time
import os

# POSIX TZ string format
TZ_AUCKLAND = "NZST-12NZDT-13,M10.1.0/02:00:00,M3.3.0/03:00:00"

def job():
    return True

class mock_datetime:
    """
    Monkey-patch datetime for predictable results
    """

    def __init__(self, year, month, day, hour, minute, second=0, zone=None):
        self.year = year
        self.month = month
        self.day = day
        self.hour = hour
        self.minute = minute
        self.second = second
        self.zone = zone
        self.original_datetime = None
        self.original_zone = None

    def __enter__(self):
        class MockDate(datetime.datetime):
            @classmethod
            def today(cls):
                return cls(self.year, self.month, self.day)

            @classmethod
            def now(cls):
                return cls(
                    self.year,
                    self.month,
                    self.day,
                    self.hour,
                    self.minute,
                    self.second,
                )

        self.original_datetime = datetime.datetime
        datetime.datetime = MockDate

        self.original_zone = os.environ.get("TZ")
        if self.zone:
            os.environ["TZ"] = self.zone
            time.tzset()

        return MockDate(
            self.year, self.month, self.day, self.hour, self.minute, self.second
        )

    def __exit__(self, *args, **kwargs):
        datetime.datetime = self.original_datetime
        if self.original_zone:
            os.environ["TZ"] = self.original_zone
            time.tzset()

with mock_datetime(2023, 9, 18, 10, 00, 0, TZ_AUCKLAND):
    # We've set the date to 10:00 on Monday 18 September NZST (which is 22:00 on Sunday 17 September UTC)

    # Testing correct application of every().day
    schedule.clear()
    next = schedule.every().day.at("23:00", "UTC").do(job).next_run
    print(
    f"Current local time: {datetime.datetime.now()}\n"
    f"Next run time: {schedule.jobs[0].next_run} (expected: 2023-09-18 11:00:00)\n"
    f"Idle time: {round(schedule.idle_seconds() / 3600)} hours (expected: 1 hours)\n"
    )

The output from this is:

Current local time: 2023-09-18 10:00:00
Next run time: 2023-09-19 11:00:00 (expected: 2023-09-18 11:00:00)
Idle time: 25 hours (expected: 1 hours)

Which as you can see doesn't have the expected next run time or idle time.

alkanex-xyz commented 8 months ago

can you check if #604 solves your problems?

bellt commented 8 months ago

Doing some quick checks, it looks like that does solve the problem! That commit isn't working with mock_datetime but I came up with a few other code snippets and it worked as expected for those. Fingers crossed that this will also fix #598 Thanks