python schedule jobs with different timezones

Question:

I want to schedule a python function to run everyday at a certain time for a list of customers with different timezones.

This is basically what I want to do:

import schedule
import time

def job(text):
    print("Hello " + text)

def add_job(user_tz, time, text):
    schedule.every().day.at(time).do(job(text)) 
    # the above adds all jobs at local time, I want to use different timezones with these

def run_job():
    while(1):
        schedule.run_pending()
        time.sleep(1)

if __name__=='__main__':
    add_job('America/New_York', "12:00", 'New York')
    add_job('Europe/London', "12:00", 'London')
    run_job()

I am using this for posting/receiving some stuff using flask and an external API.

Celery or heroku scheduler or something heavy is not what I am looking for, something lightweight and pythonic for debian(or nix) env would be ideal. I have looked into scheduler, tzcron and APScheduler, but could not figure out how we would be able to use them with timezones.

Also I tried using crontab but could not figure out how to add jobs at run time, since I want to be able to add/remove jobs using the above mentioned functions at runtime as well.

I have some experience with python, but its my first problem with timezones and I dont know much about this, so please feel free to enlighten me if there is something I missed or if there is any other way of doing it.

Thanks!

Asked By: skybunk

||

Answers:

The arrow library is great for this, and much simpler than the standard date/time (imo). arrow docs.

import arrow
from datetime import datetime

now = datetime.now()
atime = arrow.get(now)
print(now)
print (atime)

eastern = atime.to('US/Eastern')
print (eastern)
print (eastern.datetime)

2017-11-17 09:53:58.700546
2017-11-17T09:53:58.700546+00:00
2017-11-17T04:53:58.700546-05:00
2017-11-17 04:53:58.700546-05:00

I would change your “add_job” method modify all of my incoming dates to a standard time zone (utc for example).

Answered By: SteveJ

The described problem sounds like the scheduler library for python provides a solution out of the box that requires no further customization by the user.
The scheduler library is designed so that jobs can be scheduled in different timezones, it is irrelevant with which timezone the scheduler is created and in which independent timezones the jobs are scheduled.

Disclosure: I’m one of the authors of the scheduler library

For demonstration, I have adapted an example from the documentation to the question:

import datetime as dt
from scheduler import Scheduler
import scheduler.trigger as trigger

# Create a payload callback function
def useful():
    print("Very useful function.")

# Instead of setting the timezones yourself you can use the `pytz` library
tz_new_york = dt.timezone(dt.timedelta(hours=-5))
tz_wuppertal = dt.timezone(dt.timedelta(hours=2))
tz_sydney = dt.timezone(dt.timedelta(hours=10))

# can be any valid timezone
schedule = Scheduler(tzinfo=dt.timezone.utc)

# schedule jobs
schedule.daily(dt.time(hour=12, tzinfo=tz_new_york), useful)
schedule.daily(dt.time(hour=12, tzinfo=tz_wuppertal), useful)
schedule.daily(dt.time(hour=12, tzinfo=tz_sydney), useful)

# Show a table overview of your jobs
print(schedule)
max_exec=inf, tzinfo=UTC, priority_function=linear_priority_function, #jobs=3

type     function         due at              tzinfo          due in      attempts weight
-------- ---------------- ------------------- ------------ --------- ------------- ------
DAILY    useful()         2021-07-20 12:00:00 UTC-05:00      1:23:39         0/inf      1
DAILY    useful()         2021-07-21 12:00:00 UTC+10:00     10:23:39         0/inf      1
DAILY    useful()         2021-07-21 12:00:00 UTC+02:00     18:23:39         0/inf      1

Execute jobs using a simple loop:

import time
while True:
    schedule.exec_jobs()
    time.sleep(1)  # wait a second

Edit: An asyncio example is available in the doc too.

Answered By: jpotyka