diff --git a/README.rst b/README.rst index 7811675..aa580f3 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ CircuitPython Weekly Meeting Notes Each week, members of the CircuitPython community meet on `the Adafruit Discord `_ to discuss all things CircuitPython. The meetings are recorded and made `available on YouTube `_ with links to notes in this repo. These notes include time codes to specific sections of the video so that one can only listen to portions of interest. -The weekly happens normally at 2pm ET/11am PT on Mondays. Check the #circuitpython channel for notices of change in time and links to past episodes. +The weekly happens normally at 2pm ET/11am PT on Mondays. Check the #circuitpython channel for notices of change in time and links to past episodes. You can also subscribe to the meeting calendar `calendar.rst <`https://raw.githubusercontent.com/adafruit/{{ full_repo_name }}/master/README.rst>`_. Contributing ============ diff --git a/generate_calendar.py b/generate_calendar.py new file mode 100644 index 0000000..a211e4b --- /dev/null +++ b/generate_calendar.py @@ -0,0 +1,77 @@ +# Makes the weekly meeting schedule, following some rules: +# * Recognize a bunch of US-centric holidays and move meeting from Mon -> Tue +# * Put in special notices when US daylight/standard changes occur +# * Never hold a meeting from December 23 through December 31 inclusive +import datetime +import sys + +import pytz +import icalendar +from holidays import CountryHoliday + +hols = CountryHoliday('US', state='NY') +tz = pytz.timezone('US/Eastern') +meeting_duration = datetime.timedelta(seconds=3600) + +def localize(d): + """pytz says US/Eastern, but ical wants US-Eastern""" + d = tz.localize(d) + d.tzinfo.zone = d.tzinfo.zone.replace('/', '-') + return d + +now = localize(datetime.datetime.now()) + +def first_monday(year): + d = datetime.datetime(year, 1, 2, 14) + while d.weekday() != 0: + d += datetime.timedelta(days=1) + return d + +def add_holiday_notice(calendar, d, note): + d = localize(d) + event = icalendar.Event() + event.add('summary', note + ' -- Meeting Postponed due to holiday') + event.add('dtstart', icalendar.vDatetime(d)) + event.add('dtend', icalendar.vDatetime(d + meeting_duration)) + event.add('dtstamp', now) + calendar.add_component(event) + +def add_meeting_notice(calendar, d, note): + d = localize(d) + event = icalendar.Event() + event.add('summary', 'CircuitPython Discord Meeting' + note) + event.add('dtstart', icalendar.vDatetime(d)) + event.add('dtend', icalendar.vDatetime(d + meeting_duration)) + event.add('dtstamp', icalendar.vDatetime(now)) + if 0: # This doesn't work, makes google not show the calendar at all + event.add('conference', + 'https://adafru.it/discord', + parameters= {'VALUE':'URI'}) + calendar.add_component(event) + +def make_calendar(year): + c = icalendar.Calendar() + c.add('prodid', '-//circuitpython weekly meeting generator//circuitpython.org//') + c.add('version', '0.0.0-beta0') + d0 = first_monday(year) + olddst = None + while d0 < datetime.datetime(year, 12, 23): + d = d0 + hol = hols.get(d, None) + if hol is not None: + add_holiday_notice(c, d, hol) + d = d + datetime.timedelta(days=1) + dst = tz.utcoffset(d) + if dst != olddst: + note = '\n(1PM in UTC%+d)' % ( + dst.total_seconds()//3600) + olddst = dst + else: + note = '' + add_meeting_notice(c, d, note) + d0 += datetime.timedelta(days=7) + return c + +if __name__ == "__main__": + for arg in sys.argv[1:]: + sys.stdout.buffer.write(make_calendar(int(arg)).to_ical()) diff --git a/meeting.ical b/meeting.ical new file mode 100644 index 0000000..fb14623 --- /dev/null +++ b/meeting.ical @@ -0,0 +1,340 @@ +BEGIN:VCALENDAR +VERSION:0.0.0-beta0 +PRODID:-//circuitpython weekly meeting generator//circuitpython.org// +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting\n(1PM in UTC-5) +DTSTART;TZID=US-Eastern:20200106T140000 +DTEND;TZID=US-Eastern:20200106T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200113T140000 +DTEND;TZID=US-Eastern:20200113T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:Martin Luther King\, Jr. Day -- Meeting Postponed due to holiday +DTSTART;TZID=US-Eastern:20200120T140000 +DTEND;TZID=US-Eastern:20200120T150000 +DTSTAMP;VALUE=DATE-TIME:20200301T204058Z +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200121T140000 +DTEND;TZID=US-Eastern:20200121T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200127T140000 +DTEND;TZID=US-Eastern:20200127T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200203T140000 +DTEND;TZID=US-Eastern:20200203T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200210T140000 +DTEND;TZID=US-Eastern:20200210T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:Washington's Birthday -- Meeting Postponed due to holiday +DTSTART;TZID=US-Eastern:20200217T140000 +DTEND;TZID=US-Eastern:20200217T150000 +DTSTAMP;VALUE=DATE-TIME:20200301T204058Z +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200218T140000 +DTEND;TZID=US-Eastern:20200218T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200224T140000 +DTEND;TZID=US-Eastern:20200224T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200302T140000 +DTEND;TZID=US-Eastern:20200302T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting\n(1PM in UTC-4) +DTSTART;TZID=US-Eastern:20200309T140000 +DTEND;TZID=US-Eastern:20200309T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200316T140000 +DTEND;TZID=US-Eastern:20200316T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200323T140000 +DTEND;TZID=US-Eastern:20200323T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200330T140000 +DTEND;TZID=US-Eastern:20200330T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200406T140000 +DTEND;TZID=US-Eastern:20200406T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200413T140000 +DTEND;TZID=US-Eastern:20200413T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200420T140000 +DTEND;TZID=US-Eastern:20200420T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200427T140000 +DTEND;TZID=US-Eastern:20200427T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200504T140000 +DTEND;TZID=US-Eastern:20200504T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200511T140000 +DTEND;TZID=US-Eastern:20200511T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200518T140000 +DTEND;TZID=US-Eastern:20200518T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:Memorial Day -- Meeting Postponed due to holiday +DTSTART;TZID=US-Eastern:20200525T140000 +DTEND;TZID=US-Eastern:20200525T150000 +DTSTAMP;VALUE=DATE-TIME:20200301T204058Z +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200526T140000 +DTEND;TZID=US-Eastern:20200526T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200601T140000 +DTEND;TZID=US-Eastern:20200601T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200608T140000 +DTEND;TZID=US-Eastern:20200608T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200615T140000 +DTEND;TZID=US-Eastern:20200615T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200622T140000 +DTEND;TZID=US-Eastern:20200622T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200629T140000 +DTEND;TZID=US-Eastern:20200629T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200706T140000 +DTEND;TZID=US-Eastern:20200706T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200713T140000 +DTEND;TZID=US-Eastern:20200713T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200720T140000 +DTEND;TZID=US-Eastern:20200720T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200727T140000 +DTEND;TZID=US-Eastern:20200727T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200803T140000 +DTEND;TZID=US-Eastern:20200803T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200810T140000 +DTEND;TZID=US-Eastern:20200810T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200817T140000 +DTEND;TZID=US-Eastern:20200817T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200824T140000 +DTEND;TZID=US-Eastern:20200824T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200831T140000 +DTEND;TZID=US-Eastern:20200831T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:Labor Day -- Meeting Postponed due to holiday +DTSTART;TZID=US-Eastern:20200907T140000 +DTEND;TZID=US-Eastern:20200907T150000 +DTSTAMP;VALUE=DATE-TIME:20200301T204058Z +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200908T140000 +DTEND;TZID=US-Eastern:20200908T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200914T140000 +DTEND;TZID=US-Eastern:20200914T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200921T140000 +DTEND;TZID=US-Eastern:20200921T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20200928T140000 +DTEND;TZID=US-Eastern:20200928T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201005T140000 +DTEND;TZID=US-Eastern:20201005T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:Columbus Day -- Meeting Postponed due to holiday +DTSTART;TZID=US-Eastern:20201012T140000 +DTEND;TZID=US-Eastern:20201012T150000 +DTSTAMP;VALUE=DATE-TIME:20200301T204058Z +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201013T140000 +DTEND;TZID=US-Eastern:20201013T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201019T140000 +DTEND;TZID=US-Eastern:20201019T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201026T140000 +DTEND;TZID=US-Eastern:20201026T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting\n(1PM in UTC-5) +DTSTART;TZID=US-Eastern:20201102T140000 +DTEND;TZID=US-Eastern:20201102T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201109T140000 +DTEND;TZID=US-Eastern:20201109T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201116T140000 +DTEND;TZID=US-Eastern:20201116T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201123T140000 +DTEND;TZID=US-Eastern:20201123T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201130T140000 +DTEND;TZID=US-Eastern:20201130T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201207T140000 +DTEND;TZID=US-Eastern:20201207T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201214T140000 +DTEND;TZID=US-Eastern:20201214T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +BEGIN:VEVENT +SUMMARY:CircuitPython Discord Meeting +DTSTART;TZID=US-Eastern:20201221T140000 +DTEND;TZID=US-Eastern:20201221T150000 +DTSTAMP;TZID=US-Eastern:20200301T154058 +END:VEVENT +END:VCALENDAR diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8dcb723 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +holidays +icalendar +pytz