Search code examples
pythondatetimelist-comprehension

List comprehension conditionals for datetime objects


I am writing the following function that returns the last day of every month between two given dates:

import datetime as dt

def dates_list_last_day_of_month(start_date=(2000,1,1),end_date=(2023,4,26)):

    start_date = dt.date(*start_date)
    end_date = dt.date(*end_date)

    def last_day_of_month(year, month):
        next_month = dt.date(year, month, 1) + dt.timedelta(days=32)
        return next_month.replace(day=1) - dt.timedelta(days=1)
    
    last_days = []
    for year in range(start_date.year,end_date.year+1):
        for month in range(1,13):
            date = last_day_of_month(year,month)
            if start_date < date and date < end_date:
                last_days.append(date)
    return last_days

The above function works as intended and produces the correct list of dates. I, however, first tried to write this function using a list comprehension but couldn't mangage to make it work. This was the code:

import datetime as dt

def dates_list_last_day_of_month(start_date=(2000,1,1),end_date=(2023,4,26)):

    start_date = dt.date(*start_date)
    end_date = dt.date(*end_date)

    def last_day_of_month(year, month):
        next_month = dt.date(year, month, 1) + dt.timedelta(days=32)
        return next_month.replace(day=1) - dt.timedelta(days=1)
    
    date = dt.date(1,1,1)
    last_days = [(date:=last_day_of_month(year,month)) for year in range(start_date.year,end_date.year+1) for month in range(1,13) if (start_date < date and date < end_date)]
    
    return last_days

As is, the output of the second function is an empty list. Trying with different combinantions of the condition in the comprehension and the initial declaration of 'date' yields different outputs, but none are the desired list. Some have dates ranging from the begining of the start date year, others include dates until the end of the end_date year.

How can the loops in the first code block be written as a list comprehension? Does the condition in the comprehension not work the same way it does in a for loop?

Thanks in advance!


Solution

  • Your assignment occurs after the condition so the value of date is still dt.date(1,1,1) when comparing (start_date < date and date < end_date).

    Try writing you comprehension as a loop to better understand what's going on. You should write it as follows:

    last_days = [date for year in range(start_date.year,end_date.year+1) for month in range(1,13) if (start_date < (date:=last_day_of_month(year,month)) and date < end_date)]