Skip to content

Instantly share code, notes, and snippets.

@knuxify
Created January 2, 2022 17:54
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 knuxify/58ce0f493835299f0e5e18b6b8748c7a to your computer and use it in GitHub Desktop.
Save knuxify/58ce0f493835299f0e5e18b6b8748c7a to your computer and use it in GitHub Desktop.
# coding: utf-8
"""
Generates calendar for trash pickup dates.
(Note: there are plenty of hardcoded variables here, and in general the whole thing
is written half-way in Polish; adapt the code to your own needs yourself.
No warranty provided, caveat emptor.)
"""
from datetime import date, timedelta
import re
YEAR = 2022
OVERRIDES = {
date(YEAR, 1, 6): {'papier': date(YEAR, 1, 7), 'metale': date(YEAR, 1, 7)}
}
calendar = {}
first_weekday = date(YEAR, 1, 1).weekday()
def get_first_instance_of_weekday(weekday):
date_object = date(YEAR, 1, 1)
date_object += timedelta(days=weekday-first_weekday, weeks=1)
return date_object
def generate_days(weekday, every, type, skip=0, months=[1,2,3,4,5,6,7,8,9,10,11,12]):
try:
calendar[type]
except KeyError:
calendar[type] = []
print(type)
date_object = get_first_instance_of_weekday(weekday)
if skip > 0:
date_object += timedelta(weeks=skip)
if date_object.month in months:
original_date = date_object
if date_object in OVERRIDES.keys() and type in OVERRIDES[date_object].keys():
print("Found override: " + str(date_object) + " -> " + str(OVERRIDES[date_object][type]))
date_object = OVERRIDES[date_object][type]
calendar[type].append(date_object)
date_object = original_date
while date_object.year == YEAR:
date_object += timedelta(days=every*7)
if date_object.year != YEAR:
return
original_date = date_object
if date_object in OVERRIDES.keys() and type in OVERRIDES[date_object].keys():
print("Found override: " + str(date_object) + " -> " + str(OVERRIDES[date_object][type]))
date_object = OVERRIDES[date_object][type]
if date_object.month in months:
calendar[type].append(date_object)
date_object = original_date
# The weekday variable uses weekdays internally;
# thus, Monday = 0 and Sunday = 6
# Syntax:
# weekday = 0-6, day of the week
# every = every x weeks
# skip = skip x first weeks
# months = list of months to apply rule to
print("Generating day info...")
generate_days(weekday=CHANGEME, every=CHANGEME, type='mieszane')
generate_days(weekday=CHANGEME, every=CHANGEME, type='papier')
generate_days(weekday=CHANGEME, every=CHANGEME, type='metale')
generate_days(weekday=CHANGEME, skip=CHANGEME, every=CHANGEME, type='szkło')
generate_days(weekday=CHANGEME, skip=CHANGEME, every=CHANGEME type='bioodpady', months=[1,2,3,12])
generate_days(weekday=CHANGEME, skip=CHANGEME, every=CHANGEME, type='bioodpady', months=[4,5,6,7,8,9,10,11])
#
# Generate table
#
class Table:
def __init__(self, rows, columns):
self.rows = 0
self.columns = columns
self.table = []
for row in range(0, rows-1):
self.add_row()
def add_row(self):
r = []
for col in range(0, self.columns):
r.append([])
self.table.append(r)
self.rows += 1
def set(self, row, column, value):
if row >= self.rows:
self.add_row()
self.table[row][column] = value
def get(self, row, column):
return self.table[row][column]
def dump_html(self):
html = '<table>\n'
for row in range(0,self.rows):
html += '<tr>\n'
for column in range(0,self.columns):
try:
html += self.table[row][column] + '\n'
except:
pass
html += '</tr>\n'
html += '</table>'
return html
color_for_type = {
'mieszane': ('#000', '#fff', 'Mieszane'),
'papier': ('#4472c4', '#fff', 'Papier'),
'metale': ('#ffc000', '#000', 'Metale'),
'bioodpady': ('#c45911', '#000', 'Bio'),
'szkło': ('#70ad47', '#000', 'Szkło')
}
tables = []
polish_month_names = ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień']
def week_in_month_of_day(_date):
first_week_no = date(YEAR, _date.month, 1).isocalendar().week
current_week_no = _date.isocalendar().week
if _date.month == 1:
# Sometimes the first few days of a year land on the last week
# of the last year, so suddenly this turns to 52... here's a
# workaround.
if first_week_no > 7:
first_week_no = 0
if current_week_no > 7:
current_week_no = 0
return current_week_no - first_week_no
def generate_month_table(month):
table = Table(5,8)
day = 1
_date = date(YEAR, month, day)
count = 0
for dayname in ['Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela']:
table.set(0, count, '<th>' + dayname + '</th>')
table.set(1, count, '<td></td>') # Set empty cells for the first few days
count += 1
while _date.month == month:
weekno = week_in_month_of_day(_date)
table.set(weekno+1, _date.weekday(), '<td>' + str(day) + '</td>')
_date += timedelta(days=1)
day += 1
# Set empty cells for the last few days
for column in range(0, 7):
if not table.get(-1, column):
table.set(-1, column, '<td></td>')
# Add legend
lrow = 1
for bg, fg, pname in color_for_type.values():
table.set(lrow, 7, '<td class="legend" style="background-color: #fff; color: ' + bg + '; font-weight: bold;">' + pname + '</td>')
lrow += 1
return table
styled_rows = []
class StyledRow:
def __init__(self, color, day):
self.day = str(day)
self.colors = [color]
def add_color(self, color):
self.colors.append(color)
def dump_html(self):
color_count = len(self.colors)
html = '<td class="styled" style="'
if color_count == 1:
color = self.colors[0]
html += 'background-color: ' + color[0] + '; color: ' + color[1] + ';'
else:
html += 'background: linear-gradient(90deg,'
count = 1
for color in self.colors:
stop1 = str(((100 / len(self.colors)) * (count - 1))) + '%'
stop2 = str(((100 / len(self.colors)) * (count))) + '%'
html += color[0] + ' ' + stop1 + ', ' + color[0] + ' ' + stop2
if count != len(self.colors):
html += ','
count += 1
html += '); color: #fff;'
html += '">' + self.day + '</td>'
return html
def set_row_for_day(table, _date, color):
weekno = week_in_month_of_day(_date)
if not (weekno+1, _date.weekday()) in styled_rows:
styled_rows.append((weekno+1, _date.weekday()))
table.set(weekno+1, _date.weekday(), StyledRow(color, _date.day))
else:
table.get(weekno+1, _date.weekday()).add_color(color)
print("Generating tables...")
for month in [1,2,3,4,5,6,7,8,9,10,11,12]:
table = generate_month_table(month)
for type, days in calendar.items():
color = color_for_type[type]
for day in days:
if day.month == month:
set_row_for_day(table, day, color)
for styledrow in styled_rows:
try:
table.set(styledrow[0], styledrow[1], table.get(styledrow[0], styledrow[1]).dump_html())
except:
pass
styled_rows = []
tables.append(table)
print("Exporting...")
fileout = open("html-table.html", "w")
for styledrow in styled_rows:
try:
table.set(styledrow[0], styledrow[1], table.get(styledrow[0], styledrow[1]).dump_html())
except:
pass
output = """<!DOCTYPE html>
<html>
<head>
<title>Harmonogram odbioru odpadów """ + str(YEAR) + """</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
body { width: 21cm; margin: 0 auto; margin-bottom: 20px; font-family: sans-serif; }
h2 { text-align: center; }
table { width: 100%; border-collapse: collapse; margin-bottom: 2.5cm; }
tr { width: 100%; }
td, th { border: 2px #333 solid; text-align: center; }
td.styled { font-weight: bold; -webkit-text-stroke: 1px black; color: #fff !important; }
</style>
</head>
<body>"""
monthno = 0
for table in tables:
output += '<div class="tablecontainer">'
monthname = '<h2>' + polish_month_names[monthno] + '</h2>\n'
output += monthname + table.dump_html()
monthno += 1
output += '</div>'
output += """
</body>
</html>"""
fileout.write(output)
print("Done! See html-table.html.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment