Created
January 2, 2022 17:54
-
-
Save knuxify/58ce0f493835299f0e5e18b6b8748c7a 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
# 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