agronholm / apscheduler

Task scheduling library for Python
MIT License
5.98k stars 694 forks source link

Inconsistent usage of timezone arguments #836

Open komodovaran opened 6 months ago

komodovaran commented 6 months ago

Things to check first

Version

3.10.4

What happened?

Scenario: I want a job to run at 12 AM locally, in a given timezone. For Singapore, which I've arbitrarily chosen because of the big difference, this is equal to 4 AM UTC.

Screenshot 2024-01-04 at 15 29 21

So I read that the scheduler takes a timezone and set it up like

import apscheduler

print(apscheduler.__version__)
from zoneinfo import ZoneInfo

import sqlalchemy
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.triggers.cron import CronTrigger
from apscheduler.schedulers.background import BackgroundScheduler

CONNECTION_STRING = (
    "mysql+mysqlconnector://your_database_here"
)

engine = sqlalchemy.create_engine(CONNECTION_STRING)

# Create a JobStore in the table _Jobs
mysql_jobstore_config = {
    "default": SQLAlchemyJobStore(
        engine=engine,
        tablename="_Jobs",
    )
}

# create a scheduler in Singapore timezone
scheduler = BackgroundScheduler(
    jobstores=mysql_jobstore_config, timezone=ZoneInfo("Asia/Singapore")
)

def job():
    print("hello")

# add a job to the scheduler that should trigger at noon local time (UTC+8), so in UTC that's 4:00 AM
scheduler.add_job(
    func=job,
    trigger=CronTrigger(
        hour=12, minute=0, second=0, #timezone=ZoneInfo("Asia/Singapore") # This is not configured, because the scheduler is already in Singapore timezone
    ),
    id="test_job",
)

# start the scheduler
scheduler.start()
scheduler.print_jobs()

This yields

Jobstore default:
    job (trigger: cron[hour='12', minute='0', second='0'], next run at: 2024-01-05 12:00:00 UTC)

+--------+--------------------------+
|id      |next_run_time_datetime    |
+--------+--------------------------+
|test_job|2024-01-05 12:00:00.000000|
+--------+--------------------------+

So there doesn't seem to be any indication that this is going to run in some other timezone.

But if I specify the timezone in the CronTrigger (regardless of whether the scheduler has the argument or not) it yields

Jobstore default:
    job (trigger: cron[hour='12', minute='0', second='0'], next run at: 2024-01-05 12:00:00 +08)

+--------+--------------------------+
|id      |next_run_time_datetime    |
+--------+--------------------------+
|test_job|2024-01-05 04:00:00.000000|
+--------+--------------------------+

So now it looks like it's going to fire tomorrow at 4 AM, like I expect it to.


So it seems like the timezone has no effect on the scheduler. Or do I misunderstand?

How can we reproduce the bug?

See minimal example above. Requires a local MySQL instance, or similar.

agronholm commented 6 months ago

APScheduler 3.x requires pytz timezones. I'm surprised there was no warning or error. Have you tried with pytz yet? APScheduler 4.x (currently in alpha) uses ZoneInfo but it's not recommended for production yet.

komodovaran commented 6 months ago

Interestingly enough I get the exact same behavior and outcome if I use pytz.timezone instead of ZoneInfo.

injust commented 2 months ago

Seems like CronTrigger.timezone actually defaults to the local timezone: https://github.com/agronholm/apscheduler/blob/2a2210fc71683547f8b01c7d4552815c3b67c1fe/apscheduler/triggers/cron/__init__.py#L49-L59

Even though the below docstrings suggest otherwise: https://github.com/agronholm/apscheduler/blob/2a2210fc71683547f8b01c7d4552815c3b67c1fe/apscheduler/triggers/cron/__init__.py#L28-L29 https://github.com/agronholm/apscheduler/blob/2a2210fc71683547f8b01c7d4552815c3b67c1fe/apscheduler/triggers/cron/__init__.py#L94-L95

injust commented 2 months ago

In 4.0, the docstrings correctly say that CronTrigger.timezone defaults to the local timezone: https://github.com/agronholm/apscheduler/blob/c921db43dad8ad8f6cfdcc8539bfad0980b1529c/src/apscheduler/triggers/cron/__init__.py#L41-L42 https://github.com/agronholm/apscheduler/blob/c921db43dad8ad8f6cfdcc8539bfad0980b1529c/src/apscheduler/triggers/cron/__init__.py#L123-L124