pythonpython-3.xfunctiondatepython-datetime

How to calculate the first Monday of the month; python 3.3+


I need to run a monthly report on the first Monday of the month and calculate this day with Python. The code I have so far will go into a module in our ETL program and will determine if the date is actually the first day of the month. Ideally, what I need is if the Monday is the first Monday of the month, run the report (execute = 1) only on this day. Otherwise, do not run anything (execute = 0). What I have:

# Calculate first Monday of the month

# import module(s)

from datetime import datetime, date, timedelta

today = date.today() # - timedelta(days = 1)
datee = datetime.strptime(str(today), "%Y-%m-%d")

print(f'Today: {today}')

# function finds first Monday of the month given the date passed in "today"

def find_first_monday(year, month, day):
    d = datetime(year, int(month), int(day))
    offset = 0-d.weekday() #weekday = 0 means monday
    if offset < 0:
        offset+=7
    return d+timedelta(offset)

# converts datetime object to date
first_monday_of_month = find_first_monday(datee.year, datee.month, datee.day).date()

# prints the next Monday given the date that is passed as "today" 

print(f'Today\'s date: {today}')
print(f'First Monday of the month date: {first_monday_of_month}')

# if first Monday is true, execute = 1, else execute = 0; 1 will execute the next module of code

if today == first_monday_of_month:
  execute = 1
  print(execute) 
else:
  execute = 0
  print(execute)

It works assuming the date in "today" is not after the first Monday of the month. When "today" is after the first Monday of the month, it prints the next coming Monday.

Our ETL scheduler allows us to run daily, weekly, or monthly. I'm thinking I'll have to run this daily, even though this is a monthly report, and the module with this code will determine if "today" is the first Monday of the month or not. If it's not the first Monday, it will not execute the next code modules (execute = 0). I'm not confident this will actually run if "today" is the first Monday of the month since it prints the next coming Monday for any date passed in "today."

I can't seem to find the answer I need for making sure it only calculates the first Monday of the month and only runs the report on that day. Thanks in advance.


Solution

  • One way to do this is to ignore the current day value, and just use 7 instead; then you can simply subtract the weekday offset:

    from datetime import datetime, timedelta
    
    # note change to function signature
    def find_first_monday(year, month):
        d = datetime(year, int(month), 7)
        offset = -d.weekday() # weekday == 0 means Monday
        return d + timedelta(offset)
    

    This can be generalised to find the first of any day of the week in the month with a dow input where Monday = 0 and Sunday = 6. For example:

    def find_first_dow(year, month, dow):
        d = datetime(year, int(month), 7)
        offset = -((d.weekday() - dow) % 7)
        return d + timedelta(offset)
    
    for i in range(7):
         find_first_day(2024, 2, i)
    

    Output:

    datetime.datetime(2024, 2, 5, 0, 0)
    datetime.datetime(2024, 2, 6, 0, 0)
    datetime.datetime(2024, 2, 7, 0, 0)
    datetime.datetime(2024, 2, 1, 0, 0)
    datetime.datetime(2024, 2, 2, 0, 0)
    datetime.datetime(2024, 2, 3, 0, 0)
    datetime.datetime(2024, 2, 4, 0, 0)