-
Notifications
You must be signed in to change notification settings - Fork 5
/
calendar.py
109 lines (90 loc) · 3.53 KB
/
calendar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import datetime
import collections
from czech_holidays import Holidays
from dateutil.relativedelta import relativedelta
from dateutil import tz
from pyvodb import tables
DAY = datetime.timedelta(days=1)
WEEK = DAY * 7
CET = tz.gettz('Europe/Prague')
MONTH_NAMES = ('? January February March April May June July August September '
'October November December').split()
DAY_NAMES = 'Monday Tuesday Wednesday Thursday Friday Saturday Sunday'.split()
def get_calendar(db, first_year=None, first_month=None, num_months=3,
series_slugs=None):
if first_year is None:
first_year = datetime.datetime.now().year
if first_month is None:
first_month = datetime.datetime.now().month - num_months // 2
while first_month < 1:
first_month += 12
first_year -= 1
while first_month > 12:
first_month -= 12
first_year += 1
start = datetime.date(year=first_year, month=first_month, day=1)
end = start + relativedelta(months=num_months)
query = db.query(tables.Event)
query = query.filter(tables.Event.date >= start)
query = query.filter(tables.Event.date < end)
if series_slugs is not None:
query = query.filter(tables.Event.series_slug.in_(series_slugs))
events = collections.defaultdict(list)
next_occurences = collections.defaultdict(list)
for event in query:
events[event.date].append(event)
if series_slugs is not None:
query = db.query(tables.Series)
for series_slug in series_slugs:
series = query.get(series_slug)
if not series:
continue
next_occurrences = series.next_occurrences()
zero_time = datetime.time(tzinfo=CET)
start_date = datetime.datetime.combine(start, zero_time)
end_date = datetime.datetime.combine(end+relativedelta(days=1),
zero_time)
between = getattr(next_occurrences, 'between', None)
if between:
occurences = between(start_date, end_date, inc=True)
for occurence in occurences:
next_occurences[occurence.date()].append(series)
months = collections.OrderedDict()
now = start
while now < end:
months[now.year, now.month] = get_month(now.year, now.month, events,
next_occurences)
now += relativedelta(months=1)
return months
def get_month(year, month, events, next_occurences=None):
holidays = {h: h for h in Holidays(year)}
def mkday(day):
alien = (day.month != month)
return get_day(day, events=events, holidays=holidays, alien=alien,
next_occurences=next_occurences)
first_of_month = datetime.date(year, month, 1)
first = first_of_month - DAY * first_of_month.weekday()
last = first
while (last.year, last.month) <= (year, month):
last += WEEK
while (last - first) < 6 * WEEK:
last += WEEK
week = []
weeks = []
current = first
while current < last:
if current.weekday() == 0:
week = []
weeks.append(week)
week.append(mkday(current))
current += DAY
return weeks
def get_day(day, events, holidays, next_occurences=None, *, alien=False):
return {
'day': day,
'events': events[day],
'holiday': holidays.get(day),
'weekend': day.weekday() >= 5,
'next_occurences': next_occurences.get(day) if next_occurences else [],
'alien': alien,
}