ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
취리히 시 초등학교 방학일과 공휴일을 포함한 iCal 피드로, 취리히 오픈데이터에서 매일 업데이트됩니다
Abonnierbarer iCal-Feed mit den Ferien und schulfreien Tagen der Volksschule der Stadt Zürich. Aus den Daten von Open Data Zürich, täglich aktualisiert.
교육Python · HTMLGitHub @malkreide온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Subscribable iCal feed for Zurich public school holidays, generated from Open Data Zurich (CKAN)
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Subscribable iCal feed for Zurich public school holidays, generated from Open Data Zurich (CKAN) Note: This is an independent open-source project, not an official service of the City of Zurich. Data source: Open Data Zürich (dataset ssd_schulferien, CC-0-like open government data).README 전문 보기 ↗
Subscribable iCal feed for Zurich public school holidays, generated from Open Data Zurich (CKAN)
Note: This is an independent open-source project, not an official service of the City of Zurich. Data source: Open Data Zürich (dataset
ssd_schulferien, CC-0-like open government data).
The City of Zurich publishes school holidays as per-school-year static ICS files, which users must re-download and re-import every year. This project turns the underlying open data into a permanently subscribable iCalendar feed under a stable URL: calendar apps poll it automatically, and changes to holiday dates propagate to all subscribers without any manual action.
A GitHub Actions workflow fetches the CKAN datastore nightly, generates an
RFC 5545-compliant .ics file, and deploys it to GitHub Pages.
A human-readable landing page with step-by-step subscription instructions is published at malkreide.github.io/zuerich-schulferien-ics — point non-technical users there rather than at this README.
Stable feed URL:
https://malkreide.github.io/zuerich-schulferien-ics/ferien.ics
The same data is published in three cuts — subscribe to one of them:
| Feed | Contents |
|---|---|
ferien.ics | Holidays and individual school-free days. The default. |
nur-ferien.ics | Only the multi-day closures, no single days |
alles.ics | Additionally the public holidays |
ferien.ics is deliberately left unchanged: people are already subscribed to
that URL, and narrowing it after the fact would remove dates from their
calendars without anyone asking.
| Platform | How to subscribe |
|---|---|
| Apple Calendar (iOS/macOS) | Open webcal://malkreide.github.io/zuerich-schulferien-ics/ferien.ics |
| Google Calendar / Android | Open https://calendar.google.com/calendar/r?cid=webcal%3A%2F%2Fmalkreide.github.io%2Fzuerich-schulferien-ics%2Fferien.ics and confirm |
| Other clients (Nextcloud, Thunderbird, …) | Add the raw HTTPS URL as a calendar subscription |
Android users: do not simply tap the HTTPS link in a browser — that downloads a one-time static copy that never updates. Use the Google Calendar link above instead.
The feed is UTF-8 (no BOM, CRLF line endings). GitHub Pages serves it as
Content-Type: text/calendar without a charset parameter — response
headers are not configurable there. Some clients then guess wrong and render
umlauts as mojibake (Zürich instead of Zürich). This affects the fetch
only, not the file.
Known case: Windows PowerShell 5.1 decodes a response without charset
as ISO-8859-1. Set the encoding explicitly when inspecting the feed:
# Windows PowerShell 5.1 — force UTF-8
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$r = [Net.WebClient]::new()
$r.Encoding = [Text.Encoding]::UTF8
$r.DownloadString("https://malkreide.github.io/zuerich-schulferien-ics/ferien.ics") -split "`r`n" | Select-Object -First 20
PowerShell 7+ (pwsh) defaults to UTF-8, so plain Invoke-WebRequest works
there. So does curl:
curl -s https://malkreide.github.io/zuerich-schulferien-ics/ferien.ics | head -20
Calendar clients (Apple Calendar, Google Calendar, Thunderbird, Nextcloud) treat iCalendar as UTF-8 per RFC 5545 and are unaffected.
DTSTAMP comes from the source data, not the wall
clock. Same input, same bytes: the nightly run no longer makes every
subscriber re-download the feedSchulen Stadt Zürich schulfrei: prefix is
dropped and trailing parentheticals move into the descriptionSchulschluss 12 Uhr is a timed event at noon, not an all-day one — that
day is a short school day, not a day offVALUE=DATE) with correct exclusive end datesTRANSP:TRANSPARENT — holidays never block your free/busy availabilitypytest suite that runs offline in CIThe CKAN end_date is already exclusive (iCal convention). Sportferien
2026 run Feb 9–20 and are stored as 2026-02-09 → 2026-02-21. The script
therefore applies no +1 day correction — adding one would make every
holiday a day too long.
The dataset mixes school entries (prefixed Schulen Stadt Zürich) with plain
public holidays. In the window from 2024 that is 76 school entries against 97
holidays — 94 of which fall entirely inside an already school-free block, and
22 of which land on weekends only. Only the school entries are published.
Source titles run up to 137 characters. After cleanup the longest is 42; the
remainder is preserved as the event DESCRIPTION.
Some single-day records ship end_date == start_date; these are normalised
to proper one-day events.
Minor source inconsistencies — Schulschluss 12 Uhr alongside
Schulschluss um 12 Uhr, (KW29-33) alongside (KW 29-33) — are normalised.
The feed starts on 1 January of the year before last (CUTOFF_YEARS_BACK = 2,
i.e. 2024-01-01 on 2026-08-22). The
CKAN dataset reaches back to 2018; unfiltered, roughly two thirds of the
entries would be pure history. An event straddling the cutoff (e.g.
Weihnachtsferien 2023/24) is kept in full — the filter never truncates
an ongoing holiday.
UIDs hash (raw summary, start, end) — deliberately the uncleaned summary,
so shortening a title updates existing subscriptions in place instead of
resyncing them. A changed date still syncs to clients as "old event removed,
new event added" rather than an in-place update. This is intentional: it keeps
the generator stateless.
The city publishes these dates twice: as the CKAN dataset this feed is
built from, and as one static .ics per school year on the
Schulferien page.
scripts/compare_official_ics.py checks the two against each other. As of
2026-08-24, across all four offered school years, 104 records are identical
and nothing differs unexplained. The only two systematic differences favour
CKAN: the per-year .ics files cut the summer holidays at the 1 August
school-year boundary (CKAN carries the block whole), and CKAN holds one
same-span duplicate among the public holidays (Pfingsten /
, 2029-05-20) that the feed filters out anyway. There is
therefore nothing in the handover that the open dataset lacks.
requests, icalendar (see requirements.txt)pip install -r requirements-dev.txt
pytest -q # test suite, runs offline against fixtures
python generate_ics.py # writes public/ferien.ics + public/index.html
python scripts/compare_official_ics.py # needs network: compare both of the city's exports
zuerich-schulferien-ics/
├── generate_ics.py # fetch CKAN → filter → build ICS + page → sanity gate
├── tests/ # pytest suite on fixtures, no network access
├── scripts/compare_official_ics.py # cross-check against the city's own .ics downloads
├── requirements.txt
├── requirements-dev.txt
├── web/index.html # landing page template (subscription instructions)
├── docs/BETRIEB.md # runbook (German): incidents, roles, handover checklist
├── docs/GOVERNANCE-SCHULAMT-ORG.md # draft (German): rules for a Schulamt organisation
├── public/ferien.ics # generated feed (deployed to GitHub Pages)
├── public/index.html # rendered landing page (deployed alongside)
├── .github/workflows/deploy.yml # nightly cron + manual trigger, OIDC deploy, failure alarm
└── .github/workflows/keepalive.yml # monthly heartbeat, keeps the cron from being auto-disabled
The runbook lives in docs/BETRIEB.md (German): roles, what to do when the nightly build fails, and the checklist for moving the project to another account or organisation.
The published address and the source link are configurable
(PAGES_CUSTOM_DOMAIN, FEED_BASE_URL, REPO_URL as repository variables),
so a move needs no code change. UID_DOMAIN must not be changed with it:
calendar clients recognise existing subscriptions by it.
See CHANGELOG.md
Contributions are welcome — see CONTRIBUTING.md.
Please report vulnerabilities as described in SECURITY.md.
MIT License — see LICENSE
Hayal Oezkan · malkreide
Pfingstsonntag.ics