How do you maximize consecutive days off using the fewest PTO days possible? It turns out this is a surprisingly fun combinatorial optimization problem. Here is how I solved it — and built a free tool anyone can use.
The Problem
Given:
- A list of public holidays (fixed dates)
- A number of available PTO days
- A year calendar
Find: The optimal placement of PTO days that maximizes consecutive days off.
Sounds simple? It is — if you only look at one holiday at a time. But when you consider all possible placements across an entire year, the search space explodes.
Why Brute Force Doesn't Work
A naive approach would be to try every possible combination of PTO day placements. With 260 working days in a year and, say, 10 PTO days to place, you're looking at C(260, 10) — roughly 4.2 trillion combinations.
Even if you could check 1 million combinations per second, that would take about 49 days. Not exactly instant feedback.
We need a smarter approach.
The Greedy Algorithm
The key insight: public holidays create "anchor points" on the calendar. The best use of PTO days is almost always adjacent to holidays or weekends, where they "bridge" gaps and create longer consecutive stretches.
Here's the algorithm I used:
Step 1: Identify All Candidate Days
First, we find every day that could potentially be a high-value PTO day. These are:
function findCandidateDays(holidays, weekends, ptoDays) {
const candidates = [];
for (let i = 0; i < 365; i++) {
const day = getDate(i);
if (isWeekend(day) || holidays.includes(day)) continue;
// Score this day by how many consecutive days off it would create
const score = scoreDay(day, holidays, weekends);
candidates.push({ day, score });
}
return candidates.sort((a, b) => b.score - a.score);
}
Step 2: Score Each Day
The scoring function is the heart of the algorithm:
function scoreDay(day, holidays, weekends) {
let consecutiveDays = 1; // The day itself
let daysOff = 0;
// Count consecutive days off BEFORE this day
let checkDay = addDays(day, -1);
while (isDayOff(checkDay, holidays, weekends)) {
consecutiveDays++;
checkDay = addDays(checkDay, -1);
}
// Count consecutive days off AFTER this day
checkDay = addDays(day, 1);
while (isDayOff(checkDay, holidays, weekends)) {
consecutiveDays++;
checkDay = addDays(checkDay, 1);
}
return consecutiveDays;
}
A day that bridges a holiday and a weekend scores much higher than an isolated Tuesday in the middle of nowhere.
Step 3: Greedy Selection
Pick the highest-scoring day, mark it as PTO, recompute scores, repeat:
function optimize(holidays, weekends, totalPtoDays) {
const selected = [];
const usedDays = new Set();
for (let i = 0; i < totalPtoDays; i++) {
const candidates = findCandidateDays(holidays, weekends, totalPtoDays)
.filter(c => !usedDays.has(c.day));
if (candidates.length === 0) break;
const best = candidates[0];
selected.push(best);
usedDays.add(best.day);
}
return selected;
}
After each selection, we recompute because placing a PTO day changes the landscape. A day that was previously isolated might now be part of a bridge.
The Grouping Phase
Once we have our optimal days, we group them into vacation blocks:
function groupIntoStreaks(ptoDays, holidays, weekends) {
const allDaysOff = [...holidays, ...weekends, ...ptoDays].sort();
const streaks = [];
let currentStreak = [];
for (const day of allDaysOff) {
if (currentStreak.length === 0 ||
daysBetween(last(currentStreak), day) <= 1) {
currentStreak.push(day);
} else {
if (currentStreak.length >= 3) streaks.push(currentStreak);
currentStreak = [day];
}
}
return streaks.sort((a, b) => b.length - a.length);
}
Complexity Analysis
- Time: O(n * p) where n = working days in year, p = PTO days
- Space: O(n) for storing candidate scores
For a typical year with 10 PTO days: ~2,600 operations. Instant.
The trick is that we're not trying every combination — we're making locally optimal choices (greedy) and re-evaluating. This works because the scoring function captures the global structure.
Real-World Results
With this algorithm, here's what 5 PTO days can buy you in 2026:
- 5 PTO days → 18 consecutive days off around Christmas/New Year's
- 3 PTO days → 9 consecutive days off around Memorial Day
- 2 PTO days → 5 consecutive days off around July 4th
The algorithm finds these automatically. No manual calendar-staring required.
Edge Cases
A few things the algorithm handles:
- Overlapping holidays — When Christmas and New Year's are close, the algorithm recognizes the combined stretch
- Weekend proximity — A Friday holiday scores lower than a Tuesday holiday (the Friday already has adjacent weekend days)
- Month boundaries — Calendar math with JavaScript Date objects, accounting for leap years
Try It Yourself
I built this into a free, open tool called Holiday Optimizer. It has presets for multiple countries (US, UK, Canada, Germany, France, Australia, and more) and lets you input your PTO days to get an optimized plan instantly.
Check it out: Holiday Optimizer
Conclusion
What started as a "what's the best day to take off" question turned into a fun optimization problem. The greedy approach works surprisingly well because the structure of holidays and weekends creates natural anchor points.
If you're interested in the algorithm or want to contribute, the project is open source. Fork it, break it, improve it.
Now stop reading and go plan your vacations. Your future self will thank you.
Have you tried optimizing your PTO? What's the best stretch of days off you've ever gotten? Drop a comment below.
Top comments (0)