Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions cloudflare/src/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,24 @@ export function buildEntries(config, startYear, endYear) {
date = getNthWeekday(year, holiday.month, holiday.weekday, holiday.nth);
}

const holidayEntries = [{ name: holiday.name, date }];
if (holiday.observed) {
date = adjustForObservance(date);
const observedDate = adjustForObservance(date);
if (observedDate.getTime() !== date.getTime()) {
holidayEntries.push({ name: `${holiday.name} (Observed)`, date: observedDate });
}
}

if (!isDateInRange(date, startDate, endDate)) {
continue;
}
for (const entry of holidayEntries) {
if (!isDateInRange(entry.date, startDate, endDate)) {
continue;
}

const dedupeKey = `${holiday.name}:${formatIsoDate(date)}`;
if (!seen.has(dedupeKey)) {
seen.add(dedupeKey);
entries.push({ name: holiday.name, date });
const dedupeKey = `${entry.name}:${formatIsoDate(entry.date)}`;
if (!seen.has(dedupeKey)) {
seen.add(dedupeKey);
entries.push(entry);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion devbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"shell": {
"init_hook": [
"poetry install",
"poetry shell"
"eval \"$(poetry env activate)\""
]
}
}
4 changes: 2 additions & 2 deletions devbox.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"poetry@latest": {
"last_modified": "2025-03-22T01:19:59Z",
"plugin_version": "0.0.4",
"plugin_version": "0.0.5",
"resolved": "github:NixOS/nixpkgs/0740f6f238767d4caf9afe774d3e88105766dfc6#poetry",
"source": "devbox-search",
"version": "2.1.1",
Expand Down Expand Up @@ -71,7 +71,7 @@
},
"python@latest": {
"last_modified": "2025-03-11T17:52:14Z",
"plugin_version": "0.0.4",
"plugin_version": "0.0.5",
"resolved": "github:NixOS/nixpkgs/0d534853a55b5d02a4ababa1d71921ce8f0aee4c#python313",
"source": "devbox-search",
"version": "3.13.2",
Expand Down
2 changes: 0 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 18 additions & 12 deletions src/generate_calendar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,19 +248,25 @@ def build_holiday_entries(
for holiday in year_holidays:
holiday_name = cast(str, holiday["name"])
holiday_date = cast(calendar_date, holiday["date"])
entries = [(holiday_name, holiday_date)]
if holiday.get("observed", False):
holiday_date = adjust_for_observance(holiday_date)

if holiday_date < range_start or holiday_date > range_end:
continue

holiday_key = (holiday_name, holiday_date)
if holiday_key in seen:
logger.warning("Skipping duplicate holiday definition for %s on %s", *holiday_key)
continue

seen.add(holiday_key)
holidays.append({"name": holiday_name, "date": holiday_date})
observed_date = adjust_for_observance(holiday_date)
if observed_date != holiday_date:
entries.append((f"{holiday_name} (Observed)", observed_date))

for entry_name, entry_date in entries:
if entry_date < range_start or entry_date > range_end:
continue

holiday_key = (entry_name, entry_date)
if holiday_key in seen:
logger.warning(
"Skipping duplicate holiday definition for %s on %s", *holiday_key
)
continue

seen.add(holiday_key)
holidays.append({"name": entry_name, "date": entry_date})

return holidays

Expand Down
26 changes: 22 additions & 4 deletions tests/test_generate_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,35 @@ def test_build_holiday_entries_rejects_inverted_year_range() -> None:
build_holiday_entries(2026, 2025)


def test_build_holiday_entries_observes_juneteenth() -> None:
holidays = build_holiday_entries(2027, 2027)
@pytest.mark.parametrize(
("holiday_name", "start_year", "end_year", "actual_date", "observed_date"),
[
("New Year's Day", 2021, 2022, date(2022, 1, 1), date(2021, 12, 31)),
("Juneteenth", 2027, 2027, date(2027, 6, 19), date(2027, 6, 18)),
("Independence Day", 2026, 2026, date(2026, 7, 4), date(2026, 7, 3)),
("Veterans Day", 2023, 2023, date(2023, 11, 11), date(2023, 11, 10)),
("Christmas Day", 2022, 2022, date(2022, 12, 25), date(2022, 12, 26)),
],
)
def test_build_holiday_entries_keeps_actual_holiday_when_observed_date_differs(
holiday_name: str,
start_year: int,
end_year: int,
actual_date: date,
observed_date: date,
) -> None:
holidays = build_holiday_entries(start_year, end_year)

assert {"name": "Juneteenth", "date": date(2027, 6, 18)} in holidays
assert {"name": holiday_name, "date": actual_date} in holidays
assert {"name": f"{holiday_name} (Observed)", "date": observed_date} in holidays
assert {"name": holiday_name, "date": observed_date} not in holidays


def test_build_holiday_entries_filters_observed_dates_by_actual_calendar_year() -> None:
holidays = build_holiday_entries(2021, 2021)

assert {"name": "New Year's Day", "date": date(2021, 1, 1)} in holidays
assert {"name": "New Year's Day", "date": date(2021, 12, 31)} in holidays
assert {"name": "New Year's Day (Observed)", "date": date(2021, 12, 31)} in holidays


def test_build_holiday_entries_skips_february_29_on_non_leap_years(tmp_path: Path) -> None:
Expand Down
Loading