HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Finding the date from "2nd Friday of X month"-style input

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thedateinputfridaystylemonthfindingfrom2nd

Problem

I've been working through some puzzles from exercism.io. Current puzzle asks me to return a date() from input that essentially says "The 3rd Friday of December" or "The 1st Monday of October". I'd love to hear some feedback on how to clean this code up:

def meetup_day(year, month, weekday, spec_weekday):
    import calendar
    from datetime import date

    last_day = calendar.monthrange(year, month)[1]
    wkday = {'Monday': 0, 'Tuesday': 1, 'Wednesday': 2, 'Thursday': 3, 'Friday': 4, 'Saturday': 5, 'Sunday': 6}
    schedule_day = wkday[weekday]

    if spec_weekday == "teenth":
        check_range = range(13, 20)
    elif spec_weekday == "last":
        check_range = range(last_day - 6, last_day + 1)
    else:
        spec_weekday = int(spec_weekday[0:1])
        check_range = range(7 * spec_weekday - 6, 7 * spec_weekday + 1)

    for index in check_range:
        if index > last_day:
            break
        if schedule_day == calendar.weekday(year, month, index):
            schedule_day = index

    return date(year, month, schedule_day)

meetup_day(2014, 3, "Friday", "2nd")
meetup_day(2013, 6, "Wednesday", "4th")
meetup_day(2013, 12, "Monday", "1st")
meetup_day(2015, 5, "Tuesday", "teenth")
meetup_day(2015, 4, "Thursday", "last")


I'm still fairly new to Python, and datetime stuff throws me through a loop. I chose to use calendar as well as date because I thought the syntax was easier to understand. However, I'm definitely open to ideas on more efficient ways to do this.

Quick note: The "teenth" thing:


Note that "Monteenth", "Tuesteenth", etc are all made up words. There
was a meetup whose members realised that there are exactly 7 days that
end in '-teenth'. Therefore, one is guaranteed that each day of the
week (Monday, Tuesday, ...) will have exactly one date that is named
with '-teenth' in every month.

Solution

Your code is pretty clear but can be improved using builtin capabilities of calendar: the monthcalendar method return a list of list representing each week of the selected month (zeroes are days that are not in the month). By filtering these weeks using the index of the day you are looking for, you get all the possible day of the month that are the requested day. You can then just pick the right one into this list.

Python related remarks:

  • Put your import at the beginning of the file, not into functions. It will slow you down if you are heavily calling functions that contain import statements;



  • wkday is a constant and must be declared as such: outside of the function and with proper case;



  • there is no really need to make wkday a dictionary given that you can get the same information it holds using .index on a list;



  • [optional] depending on your needs, you may want to perform proper input validations.



import calendar
from datetime import date

DAY_NAMES = [day for day in calendar.day_name]

def meetup_day(year, month, weekday, spec_weekday):
    day_index = DAY_NAMES.index(weekday)
    possible_dates = [
        week[day_index]
        for week in calendar.monthcalendar(year, month)
        if week[day_index]] # remove zeroes

    if spec_weekday == 'teenth':
        for day_num in possible_dates:
            if 13 <= day_num <= 19:
                return date(year, month, day_num)
    elif spec_weekday == 'last':
        day_index = -1
    elif spec_weekday == 'first':
        day_index = 0
    else:
        day_index = int(spec_weekday[0]) - 1
    return date(year, month, possible_dates[day_index])

meetup_day(2014, 3, "Friday", "2nd")
meetup_day(2013, 6, "Wednesday", "4th")
meetup_day(2013, 12, "Monday", "1st")
meetup_day(2015, 5, "Tuesday", "teenth")
meetup_day(2015, 4, "Thursday", "last")

Code Snippets

import calendar
from datetime import date

DAY_NAMES = [day for day in calendar.day_name]

def meetup_day(year, month, weekday, spec_weekday):
    day_index = DAY_NAMES.index(weekday)
    possible_dates = [
        week[day_index]
        for week in calendar.monthcalendar(year, month)
        if week[day_index]] # remove zeroes

    if spec_weekday == 'teenth':
        for day_num in possible_dates:
            if 13 <= day_num <= 19:
                return date(year, month, day_num)
    elif spec_weekday == 'last':
        day_index = -1
    elif spec_weekday == 'first':
        day_index = 0
    else:
        day_index = int(spec_weekday[0]) - 1
    return date(year, month, possible_dates[day_index])

meetup_day(2014, 3, "Friday", "2nd")
meetup_day(2013, 6, "Wednesday", "4th")
meetup_day(2013, 12, "Monday", "1st")
meetup_day(2015, 5, "Tuesday", "teenth")
meetup_day(2015, 4, "Thursday", "last")

Context

StackExchange Code Review Q#108543, answer score: 2

Revisions (0)

No revisions yet.