Compute the next occurrence of Friday the 13th How can I get the date of the next occurrence of Friday the 13th?

Below is my attempt. It returns the correct results. I think there must be a better way of writing this without checking thirteenth &gt; start_date for every month. It might also be possible to exploit the fact that every calendar year has a Friday 13th.

import itertools
from datetime import date


def next_fri_13(start_date):
    '''Get the next Friday 13th after the specified start_date.

    Args:
        start_date (datetime.date)

    Returns:
        datetime.date: The first Friday 13th after the start_date.
    '''
    for year in itertools.count(start_date.year):
        for month in range(1, 13):
            thirteenth = date(year, month, 13)
            # Ensure that the 13th is after the start date, and is a Friday.
            if thirteenth &gt; start_date and thirteenth.weekday() == 4:
                return thirteenth


r = next_fri_13(date(2020, 2, 11))
print(r)  # Prints: 2020-03-13
I think this can be slightly simplified by using dateutils.relativedelta (since datetime.timedelta does not support months, unfortunately). This way you don't need to manually keep track of the year and month and if you ever need to implement something for e.g. next end of a month that is on a Sunday, it is way easier, because it takes care of the peculiarities for you, like months ending on different days of the month.

I would also make the magic constant 4 into a global constant called FRIDAY.

from datetime import date
from dateutil.relativedelta import relativedelta

FRIDAY = 4    # Monday is 0

def next_fri_13(start_date):
    '''Get the next Friday 13th after the specified start_date.

    Args:
        start_date (datetime.date)

    Returns:
        datetime.date: The first Friday 13th after the start_date.
    '''
    thirteenth = date(start_date.year, start_date.month, 13)
    if start_date.day &gt;= 13:
        thirteenth += relativedelta(months=1)

    while thirteenth.weekday() != FRIDAY:
        thirteenth += relativedelta(months=1)
    return thirteenth


Alternatively, you could make a generator of thirteenths days and drop all that are not a Friday using filter and use the fact that relativedelta does not only take offsets, but can also replace attributes at the same time (using the keywords without a trailing "s"):

from itertools import count

def next_fri_13(start_date):
    '''Get the next Friday 13th after the specified start_date.

    Args:
        start_date (datetime.date)

    Returns:
        datetime.date: The first Friday 13th after the start_date.
    '''
    thirteenths = (start_date + relativedelta(months=n, day=13)
                   for n in count(start_date.day &gt;= 13))
    return next(filter(lambda d: d.weekday() == FRIDAY, thirteenths))


IMO the first is easier to read, though, while this one is slightly easier to convert into a generator yielding all Friday the 13ths after start_date (just replace return next(...) with yield from ...).

In any case, there is a bit of a philosophical debate about doing

import itertools

itertools.count()


or

from itertools import count

count()


I personally tend to favor the latter, as long as it is still somewhat easy to figure out which module a function comes from, and there is no shadowing. This makes the lines a bit shorter and easier to read, especially if you use one particular module quite heavily (which the itertools module is a bit predestined for). It is also slightly faster, because you only need to do a global lookup instead of a global lookup and an attribute lookup, but that is negligible most of the time (and if it is not, you should make it a local variable anyway). But in the end the choice is yours.