List of first work days of month for any year

TrustyTony 0 Tallied Votes 2K Views Share

To be more clear, I post this 'unnecessary optimization' of Vegaseat's code in new thread instead of end of old one. Just to show that this is even simpler than checking if given day is first weekday of the month.

"""Task: calculate this list (from vegaseat
http://www.daniweb.com/software-development/legacy-and-other-languages/threads/362098/1554079#post1554079)

All first workdays of each month in 2011:
 1) Mo  01/03/2011
 2) Tu  02/01/2011
 3) Tu  03/01/2011
 4) Fr  04/01/2011
 5) Mo  05/02/2011
 6) We  06/01/2011
 7) Fr  07/01/2011
 8) Mo  08/01/2011
 9) Th  09/01/2011
10) Mo  10/03/2011
11) Tu  11/01/2011
12) Th  12/01/2011


"""

from datetime import date, timedelta

def first_workday(month, year):
    first = date(year, month, 1)
    if first.weekday() < 5:
        return first
    return first + timedelta(days=7-first.weekday())

year = 2011
for month in range(1,13):
    print(' %2i) %s' % (month, first_workday(month,year).strftime('%a %m/%d/%Y')))
    
# Produces three letter weekday name instead of two letters

Dani AI

Generated

A simple, readable alternative that complements 's datetime variants is to use the standard library's calendar.monthrange to get the weekday of the first day and compute the day-of-month directly. This avoids creating a date object just to inspect its weekday, and makes it easy to produce the two-letter weekday labels shown in the OP's sample.

from calendar import monthrange
from datetime import date

abbr2 = {'Mon':'Mo','Tue':'Tu','Wed':'We','Thu':'Th','Fri':'Fr','Sat':'Sa','Sun':'Su'}

def first_workday(month, year):
    w, _ = monthrange(year, month)     # Monday=0 .. Sunday=6
    day = 1 if w < 5 else 8 - w        # if weekend, pick the following Monday
    d = date(year, month, day)
    return d, abbr2[d.strftime('%a')]

year = 2011
for m in range(1, 13):
    d, short = first_workday(m, year)
    print(f"{m:2}) {short} {d:%m/%d/%Y}")

Notes: this treats "workday" as Monday–Friday only and therefore does not handle public holidays. For production use that must respect holidays, combine the above with a holiday set (for example from the python-holidays or workalendar libraries) and advance the date while it is a weekend or in the holiday set. calendar.monthrange already handles month lengths and leap years. Use pandas' bdate_range if you need vectorized operations across many years.

TrustyTony 888 ex-Moderator Team Colleague Featured Poster

Not only way to do it of course (in spite of Python philosophy):

"""Task: calculate the list from vegaseat
http://www.daniweb.com/software-development/legacy-and-other-languages/threads/362098/1554079#post1554079)
"""

from datetime import date, timedelta

def first_workday(month, year):
    first = date(year, month, 1)
    return first if first.weekday() < 5 else first.replace(day=8 - first.weekday())

def table(year = 2011):
    print('\n'.join(' %2i) %s' %
                    (month, first_workday(month,year).strftime('%a %m/%d/%Y'))
                    for month in range(1,13)))
    # Produces three letter weekday name instead of two letters

table()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.