Last active
July 13, 2024 21:52
-
-
Save zed/11441b4776f7bbecc830 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
"""Test functions from | |
http://stackoverflow.com/questions/28680896/how-can-i-get-the-3rd-friday-of-a-month-in-python | |
""" | |
import calendar | |
from datetime import date, datetime, time, timedelta | |
from itertools import islice | |
DAY = timedelta(1) | |
WEEK = 7*DAY | |
try: | |
from dateutil.relativedelta import relativedelta, FR # $ pip install python-dateutil | |
def third_friday_dateutil(now, delta=relativedelta(weeks=2, weekday=FR)): | |
"""the 3rd Friday of the month, not the 3rd Friday after today.""" | |
now = now.replace(day=1) # 1st day of the month | |
return now + delta | |
from dateutil.rrule import rrule, MONTHLY, FR | |
def third_friday_rrule(now): | |
r = rrule(MONTHLY, count=1, byweekday=FR, bysetpos=3, dtstart=now.replace(day=1)) | |
return r[0].date() | |
def get_third_fris_rrule(how_many, now=date.today()): | |
r = rrule(MONTHLY, count=how_many, byweekday=FR, bysetpos=3, dtstart=now+DAY) | |
return [dt.date() for dt in r] | |
except ImportError: | |
pass | |
def fridays(now): | |
"""Generate Fridays starting (including) from now.""" | |
while True: | |
if now.weekday() == calendar.FRIDAY: | |
while True: | |
yield now | |
now += WEEK | |
now += DAY | |
def next_month(now): | |
"""Return the first date that is in the next month.""" | |
return (now.replace(day=15) + 20*DAY).replace(day=1) | |
def third_friday_brute_force(now): | |
"""the 3rd Friday of the month, not the 3rd Friday after today.""" | |
return next(islice(fridays(now.replace(day=1)), 2, 3)) | |
def get_third_fris(how_many, now=date.today()): | |
result = [] | |
while len(result) < how_many: | |
fr = third_friday_brute_force(now) | |
if fr > now: # use only the 3rd Friday after today | |
result.append(fr) | |
now = next_month(now) | |
return result | |
def third_friday_adam_smith(now, c=calendar.Calendar(firstweekday=calendar.SUNDAY)): | |
year, month = now.year, now.month | |
monthcal = c.monthdatescalendar(year, month) | |
third_friday = [day for week in monthcal for day in week if | |
day.weekday() == calendar.FRIDAY and day.month == month][2] | |
return third_friday | |
def third_friday_juniorcompressor(d): | |
s = date(d.year, d.month, 15) | |
return s + timedelta(days=(calendar.FRIDAY - s.weekday()) % 7) | |
def juniorcompressor_next_third_friday(d): | |
""" Given a third friday find next third friday""" | |
d += timedelta(weeks=4) | |
return d if d.day >= 15 else d + timedelta(weeks=1) | |
def get_third_fris_juniorcompressor(n, d=date.today()): | |
"""Given a date, calculates n next third fridays""" | |
# Find closest friday to 15th of month | |
s = date(d.year, d.month, 15) | |
result = [s + timedelta(days=(calendar.FRIDAY - s.weekday()) % 7)] | |
# This month's third friday passed. Find next. | |
if result[0] <= d: | |
result[0] = juniorcompressor_next_third_friday(result[0]) | |
for i in range(n - 1): | |
result.append(juniorcompressor_next_third_friday(result[-1])) | |
return result | |
def test(functions, start=date.today(), end=None): | |
if end is None: | |
end = start.replace(year=start.year + 400) + DAY | |
d = start | |
while d < end: | |
expected = functions[0](d) | |
assert all(expected == f(d) for f in functions), (d, [(getattr(f, '__name__', f), f(d)) for f in functions]) | |
d += DAY | |
if __name__=="__main__": | |
from pprint import pprint | |
n = 6 | |
pprint(get_third_fris_rrule(n)) | |
from reporttime import get_functions_with_prefix, measure # https://gist.github.com/zed/5650097 | |
functions = get_functions_with_prefix('third_friday_') | |
test(functions) | |
measure(functions, [date.today()]) | |
functions = get_functions_with_prefix('get_third_fris') | |
assert get_third_fris_juniorcompressor(n) == get_third_fris(n) | |
measure(functions, [n]) | |
from functools import partial | |
test([partial(f, 1) for f in functions]) | |
n = 12*401 | |
assert get_third_fris_juniorcompressor(n) == get_third_fris(n) | |
"""### Output | |
[datetime.date(2015, 3, 20), | |
datetime.date(2015, 4, 17), | |
datetime.date(2015, 5, 15), | |
datetime.date(2015, 6, 19), | |
datetime.date(2015, 7, 17), | |
datetime.date(2015, 8, 21)] | |
name time ratio comment | |
third_friday_juniorcompressor 1.69 usec 1.00 [datetime.date(2015, 2, 27)] | |
third_friday_brute_force 3.38 usec 2.00 [datetime.date(2015, 2, 27)] | |
third_friday_dateutil 11.2 usec 6.61 [datetime.date(2015, 2, 27)] | |
third_friday_adam_smith 18.8 usec 11.12 [datetime.date(2015, 2, 27)] | |
third_friday_rrule 52.7 usec 31.12 [datetime.date(2015, 2, 27)] | |
name time ratio comment | |
get_third_fris_juniorcompressor 15.6 usec 1.00 [6] | |
get_third_fris 38.1 usec 2.44 [6] | |
get_third_fris_rrule 153 usec 9.77 [6] | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment