Schedule a function in Python to always run on the last Friday of the month

1

The code below shows an example of how to program, but is somewhat limited to minutes, hours, and days. I need one that also includes the specific month and day, which in my case is Friday. I got a code that gets the date last Friday of the current month, but I did not know how to integrate using schedule .

import time
import schedule
import calendar
from datetime import date
from dateutil.relativedelta import relativedelta, FR

def last_friday_of_month(month=None, year=None):
    month = month or date.today().month
    year = year or date.today().year
    return date(year, month, 1) + relativedelta(
        day=calendar.monthrange(year, month)[1],
        weekday=FR(-1)
    )

def job(string):
    print(string)

schedule.every().thursday.at("11:49").do(job, "I'm working...")

while 1:
    schedule.run_pending()
    time.sleep(1)
    
asked by anonymous 18.01.2018 / 15:58

1 answer

1

So - the schedule library does not support this. So the simplest way is for you to simply schedule the task for every Friday, and place a filter code on the function entry: if the current date is not the last Friday of the month, then return without executing.

Of course at first glance this seems to imply paste code for calculating dates and etc. inside your tarfea, which may have nothing to do with it, and still repeat that code in various tasks in which you want to do something similar .

That's where "decorators" come in - decorators are function modifiers that have a specific syntax in Python: basically they can "collapse" the code from their original function and optionally run some code before or after - code of the decorator is separate from its main function, and you use only one line to modify the behavior of your function. I explain your usage well in this answer: How do decorators work in Python?

So you can create a decorator like this:

import datetime
from functool import wraps

def only_on_last_friday(func):
   @wraps(func)
   def wrapper(*args, **kwargs):
       today = datetime.date.today()
       if today ==  last_friday_of_month(year=today.year, month=today.month):
           return func(*args, **kwargs)
       return None
   return wrapper

Ready - in combination with its function of finding the last Friday of the month, it will only execute the call the final function if it is called last Friday.

You can either apply the decorator to its final function, or simply decorate it when calling the scheduler - so the function remains normal for the rest of your code, and only the scheduler gets the modified function to run only on the date chosen:

@only_on_last_friday
def job(string):
    print(string)

schedule.every().friday.at("11:49").do(job, "I'm working...")

or:

def job(string):
    print(string)

schedule.every().friday.at("11:49").do(only_on_last_friday(job), "I'm working...")

(I do not know if you're using dateutils for other things, but if it's not, I have a version of last_friday using only the default datetime:)

from datetime import date, timedelta 

def last_friday(year, month):
    minus_one_day = timedelta(days = 1)
    next_month = date(year, month, 27) + timedelta(days=7)
    result = date(next_month.year, next_month.month, 1)
    while True:
        result -= minus_one_day
        if result.weekday() == 4:  # Friday
            return result

Taking advantage of the opportunity, if you are using this code it is important for you to have something in place that ensures the program is running even after several days on. There is a very cool Python project for this called supervisor - which can guarantee this with very little work - it's worth looking at:

link

    
19.01.2018 / 20:04