PTO CLI
An open-source PHP command-line tool for accurately calculating remaining paid time off days under German labour law, with support for accrual policies, part-time scaling, state-specific public holidays, and carry-over caps.
Overview
Calculating remaining paid time off sounds straightforward until you factor in German labour law. Entitlement accrues differently depending on the contract type, public holidays vary by federal state, part-time employees are entitled to proportionally adjusted days, and carry-over caps expire unused leave at year-end. Every tool I found either ignored these rules or got them wrong. So I built PTO CLI — a command-line tool that handles all of this correctly, installable in seconds, with no web app or spreadsheet required. It's designed for developers and anyone comfortable with a terminal who wants an accurate, policy-aware answer about their remaining leave.
My Role
I designed and built the entire tool from scratch as a personal open-source project. The core engineering challenge was modelling the business logic correctly: a flexible accrual engine that handles different policy types, a public holiday lookup aware of all 16 German federal states, proportional scaling for part-time contracts, and a carry-over system that enforces company-defined caps. I built it as a Composer-installable CLI command using the Symfony Console component, making it easy to adopt in any PHP developer workflow.
Key Contributions
- Flexible accrual engine supports monthly, anniversary, and front-loaded yearly policies — covering the most common contract structures used by employers in Germany
- State-aware public holiday calendar covers all 16 German federal states, correctly excluding non-working days from PTO counts rather than treating every weekday as a working day
- Automatic part-time scaling adjusts annual entitlement proportionally based on contracted weekly hours, matching the requirements of German labour law for reduced-hour workers
- Carry-over logic enforces company-defined caps on unused days carried into the new year and expires them on the correct date, mirroring how most German employment contracts are structured
