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

Asked

Viewed 1,949 times

1

The code below demonstrates an example of how to program, but is somewhat limited to minutes, hours and days. I need one that also includes the month and the specific day, which in my case is Friday. I got a code that gets the date last Friday of this month, but I didn’t know how to integrate using the 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)

1 answer

1


So - the Schedule library does not support this. So the simplest way will be to simply schedule the task for every Friday, and put a filter code in 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 pasting date calculation code and etc inside your tarfea, which may have nothing to do with it, and still repeat this code on various tasks where you want to do something similar.

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

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 to the final function if it is called on the last Friday.

You can either apply the decorator to your final function, or simply decorate at the time of calling the Scheduler - so the function remains normal for the rest of your code, and only the Scheduler receives the modified function to run only on the chosen date:

@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 don’t know if you’re using the dateutils for other things, but if not, I have a last_friday version using only standard 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 that the program is running, even after several days on. There’s a very cool Python project for this called supervisor - that can guarantee this with very little work - worth looking at:

http://supervisor/

  • Okay, Doctor. I’ll run some tests. Thanks for the clarification!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.