COhPy March 2016 Challenge

This is the coding challenge for the Central Ohio Python Users Group for March 2016.

Building on last month's challenge, this month's challenge will involve figuring out dates.

This challenge has three parts. Each part builds on the previous part, and feel free to do all the parts or only some. This challenge is for you, so implement it any way you want. Find a new module, or way of implementing that scratches your itches.

Part One

Given a month (say February), return a list of dates in that month that the Central Ohio Python Users Group met (in the case of February, it would return 2/22/2010, 2/28/2011, 2/27/2012, 2/25/2013, 2/24/2014, and 2/29/2015.

You can figure out those dates by implementing the following rules:

  1. The first COhPy meeting was September 28, 2009.

  2. COhPy meets the last Monday of the month, with the following exceptions:

  3. COhPy never meets in November.

  4. COhPy meets the first Monday of the month in December EXCEPT when that Monday is the 1st or 2nd of December, when it meets on the SECOND Monday.

  5. In May, to avoid Memorial Day, COhPy meets on the second-to-last Monday of the month.

Part Two

Given a set of dates (particularly the dates returned in Part One), return the high temperature in Columbus, Ohio at the airport (weather station KCMH) for each of those dates.

Here are a couple of resources to get historical weather observations:

APIs:

CSV and other data:

Part Three

Based on the data in Part Two (or whatever data you want) predict the high temperature for the next COhPy meetup. Your prediction algorithm will run on meetup day the month prior to the one you are predicting.

At the April 2016 meeting we will run your prediction algorithms, and at the May meetup, the algorithm that most closely predicted the high reported by weather station KCMH for the May meetup will receive a Python ball cap! In the event of a tie, the tied algorithms will face off to predict June (or we'll randomly decide :-)!


Part One

Given a month (say February), return a list of dates in that month that the Central Ohio Python Users Group met (in the case of February, it would return 2/22/2010, 2/28/2011, 2/27/2012, 2/25/2013, 2/24/2014, and 2/29/2015.

You can figure out those dates by implementing the following rules:

  1. The first COhPy meeting was September 28, 2009.

  2. COhPy meets the last Monday of the month, with the following exceptions:

  3. COhPy never meets in November.

  4. COhPy meets the first Monday of the month in December EXCEPT when that Monday is the 1st or 2nd of December, when it meets on the SECOND Monday.

  5. In May, to avoid Memorial Day, COhPy meets on the second-to-last Monday of the month.


get_past_cohpy_meeting_dates_of_month() in the cells below is my solution for Part One. There is also some code to demonstrate it.

In [1]:
from __future__ import print_function
In [2]:
import datetime
import calendar
In [3]:
FIRST_MEETING = datetime.date(2009, 9, 28)
FIRST_MEETING
Out[3]:
datetime.date(2009, 9, 28)
In [4]:
FIRST_MEETING.year
Out[4]:
2009
In [5]:
MONTHS_PER_YEAR = 12
In [6]:
def get_dates_for_weekday(year, month, weekday):
    '''Returns list of dates of specified month
    that are on specified weekday.
    Dates are in ascending order.
    '''
    c = calendar.Calendar()
    return [
        day_of_month
        for day_of_month, day_of_week in c.itermonthdays2(year, month)
        if day_of_month and day_of_week == weekday]
In [7]:
assert get_dates_for_weekday(2016, 4, calendar.MONDAY) == [4, 11, 18, 25]
get_dates_for_weekday(2016, 4, calendar.MONDAY)
Out[7]:
[4, 11, 18, 25]
In [8]:
def get_cohpy_meeting_date(year, month):
    '''Returns date of specified cohpy meeting as datetime.date object
    or None if there is no COhPy meeting that month.'''
    month_name = calendar.month_name[month]
    if month_name == 'November':
        return None  # COhPy does not meet in November.
    mondays = get_dates_for_weekday(year, month, calendar.MONDAY)
    if month_name == 'December':
        date = mondays[0]
        if date <= 2:
            date = mondays[1]
        return date
    elif month_name == 'May':
        return mondays[-2]
    else:
        return mondays[-1]
In [9]:
def get_cohpy_meeting_dates_of_month(month, min_date, max_date):
    '''Returns generator of datetime.date objects for
    dates of COhPy meetings in specified month
    between min_date and max_date inclusive.'''
    for year in range(min_date.year, max_date.year + 1):
        date_of_month = get_cohpy_meeting_date(year, month)
        if not date_of_month:
            continue
        date = datetime.date(year, month, date_of_month)
        if min_date <= date <= max_date:
            yield date
In [10]:
today = datetime.date.today()
day_before_today = today - datetime.timedelta(days=1)
today, day_before_today
Out[10]:
(datetime.date(2016, 4, 25), datetime.date(2016, 4, 24))
In [11]:
for d in get_cohpy_meeting_dates_of_month(2, FIRST_MEETING, day_before_today):
    print(d)
2010-02-22
2011-02-28
2012-02-27
2013-02-25
2014-02-24
2015-02-23
2016-02-29
In [12]:
# Demonstrate that get_past_cohpy_meeting_dates_of_month() works.
for month in range(1, MONTHS_PER_YEAR + 1):
    month_name = calendar.month_name[month]
    dates = list(get_cohpy_meeting_dates_of_month(month, FIRST_MEETING, day_before_today))
    if dates:
        print('Meetings in %s before %s:' % (month_name, today))
        for date in dates:
            print('    %s' % date)
    else:
        print('No meetings in %s before %s.' % (month_name, today))
Meetings in January before 2016-04-25:
    2010-01-25
    2011-01-31
    2012-01-30
    2013-01-28
    2014-01-27
    2015-01-26
    2016-01-25
Meetings in February before 2016-04-25:
    2010-02-22
    2011-02-28
    2012-02-27
    2013-02-25
    2014-02-24
    2015-02-23
    2016-02-29
Meetings in March before 2016-04-25:
    2010-03-29
    2011-03-28
    2012-03-26
    2013-03-25
    2014-03-31
    2015-03-30
    2016-03-28
Meetings in April before 2016-04-25:
    2010-04-26
    2011-04-25
    2012-04-30
    2013-04-29
    2014-04-28
    2015-04-27
Meetings in May before 2016-04-25:
    2010-05-24
    2011-05-23
    2012-05-21
    2013-05-20
    2014-05-19
    2015-05-18
Meetings in June before 2016-04-25:
    2010-06-28
    2011-06-27
    2012-06-25
    2013-06-24
    2014-06-30
    2015-06-29
Meetings in July before 2016-04-25:
    2010-07-26
    2011-07-25
    2012-07-30
    2013-07-29
    2014-07-28
    2015-07-27
Meetings in August before 2016-04-25:
    2010-08-30
    2011-08-29
    2012-08-27
    2013-08-26
    2014-08-25
    2015-08-31
Meetings in September before 2016-04-25:
    2009-09-28
    2010-09-27
    2011-09-26
    2012-09-24
    2013-09-30
    2014-09-29
    2015-09-28
Meetings in October before 2016-04-25:
    2009-10-26
    2010-10-25
    2011-10-31
    2012-10-29
    2013-10-28
    2014-10-27
    2015-10-26
No meetings in November before 2016-04-25.
Meetings in December before 2016-04-25:
    2009-12-07
    2010-12-06
    2011-12-05
    2012-12-03
    2013-12-09
    2014-12-08
    2015-12-07