Skip to content

Instantly share code, notes, and snippets.

@mnot
Last active October 6, 2022 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mnot/639ad9dd7d5577cbcc5b12c2bf9e450a to your computer and use it in GitHub Desktop.
Save mnot/639ad9dd7d5577cbcc5b12c2bf9e450a to your computer and use it in GitHub Desktop.
from collections import defaultdict
from datetime import datetime
import csv
import sys
__doc__ = """
This is a script that uses CSV input data (for example, collected by a Google Form) to find the acceptable times for a meeting.
The CSV columns are:
1. Timestamp (often collected by online forms; ignored)
2. Name
3. Timezone (from the table below)
4. When is the earliest time you can start work in that timezone? This is not when you start your working day; list the earliest you could wake up for and still be functional in the meeting.
5. When is the latest time you can meet until in that timezone? Again, this is not when your workday ends, but how late you can stay up before you won't be able to effectively participate.
"""
# timezone: (northern_summer_offset, northern_winter_offset, timeanddate_id)
# source: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# and: https://dev.timeanddate.com/docs/available-locations
tzlookup = {
"Europe/London": (1, 0, 136),
"Europe/Berlin": (2, 1, 37),
"Europe/Helsinki": (3, 2, 101),
"Asia/Kolkata": (5.5, 5.5, 44),
"Asia/Beijing": (8, 8, 33),
"Asia/Tokyo": (9, 9, 248),
"Australia/Melbourne": (10, 11, 152),
"Pacific/Auckland": (12, 13, 22),
"Pacific/Honolulu": (-10, -10, 103),
"America/Los Angeles": (-7, -8, 137),
"America/Denver": (-6, -7, 75),
"America/Chicago": (-5, -6, 64),
"America/New York": (-4, -5, 179),
}
def parse_time(instr, default):
instr = instr.strip()
if instr == "":
return default
try:
first, second = instr.split(" ", 1)
except ValueError: # no AM/PM
first = instr
second = None
hour = int(first.split(":", 1)[0])
if second:
if second.lower() == 'pm':
hour += 12
elif hour == 12:
hour += 12
else:
if hour == 0:
hour = 24
return hour # discard mins, seconds
def avail(start, end, offset):
start_utc = start - offset
end_utc = end - offset
if start_utc < 0 or end_utc < 0:
start_utc += 24
end_utc += 24
available = set()
for h in range(start_utc, end_utc):
available.add(h % 24)
return available
def tzurl(cities, hour_utc, is_summer):
if is_summer:
date = f"month=6&day=1"
else:
date = f"month=12&day=1"
time = f"hour={hour_utc}&min=0&sec=0"
city_list = list(cities)
city_components = []
for i in range(len(city_list)):
city_components.append(f"p{i}={city_list[i]}")
city_query = "&".join(city_components)
url = f"https://www.timeanddate.com/worldclock/meetingdetails.html?{date}&{time}&{city_query}"
return url
with open(sys.argv[1]) as csvfile:
reader = csv.reader(csvfile, 'excel')
summer_candidates = set(range(0,23))
winter_candidates = set(range(0,23))
cities = set()
for response in reader:
if reader.line_num != 1:
_, name, timezone, earliest, latest = response
start = parse_time(earliest, 5)
end = parse_time(latest, 24)
summer_offset, winter_offset, tdid = tzlookup[timezone.strip()]
cities.add(tdid)
summer_available = avail(start, end, summer_offset)
winter_available = avail(start, end, winter_offset)
print(f"{name}: {start} {end} {summer_offset} {summer_available}")
summer_candidates &= summer_available
winter_candidates &= winter_available
print("Agreeable (Northern) summer UTC hours:")
for candidate in summer_candidates:
print(f"* UTC+{candidate} - <{tzurl(cities, candidate, True)}>")
print()
print("Agreeable (Northern) winter UTC hours:")
for candidate in winter_candidates:
print(f"* UTC+{candidate} - <{tzurl(cities, candidate, False)}>")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment