Skip to content
Draft
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,9 @@ any) in brackets, available languages and additional holiday categories. All cou
<tr>
<td>Belgium</td>
<td>BE</td>
<td></td>
<td>Regions: VLG, WBR, GER</td>

@cubic-dev-ai cubic-dev-ai Bot May 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Clarify Belgium subdivision labels in the table: VLG/WBR/GER are school communities (Flemish/French/German-speaking), not generic “Regions”.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At README.md, line 293:

<comment>Clarify Belgium subdivision labels in the table: `VLG/WBR/GER` are school communities (Flemish/French/German-speaking), not generic “Regions”.</comment>

<file context>
@@ -290,9 +290,9 @@ any) in brackets, available languages and additional holiday categories. All cou
 <td>Belgium</td>
 <td>BE</td>
-<td></td>
+<td>Regions: VLG, WBR, GER</td>
 <td>de, en_US, fr, <strong>nl</strong>, uk</td>
-<td>BANK</td>
</file context>
Suggested change
<td>Regions: VLG, WBR, GER</td>
<td>Communities: VLG (Flemish), WBR (French), GER (German-speaking)</td>
Fix with Cubic

<td>de, en_US, fr, <strong>nl</strong>, uk</td>
<td>BANK</td>
<td>BANK, SCHOOL</td>
</tr>
<tr>
<td>Belize</td>
Expand Down
25 changes: 24 additions & 1 deletion docs/holiday_categories.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,29 @@ for date, name in sorted(germany_catholic.items()):
print(f"{date}: {name}")
```

### School Holidays Example (Belgium)

Belgium provides school holidays that depend on the educational community.
Currently supported subdivisions are:

- `VLG` → Flemish Community
- `WBR` → French Community (Wallonia + Brussels French schools)
- `GER` → German-speaking Community

To retrieve only school holidays, use the `SCHOOL` category.

#### Basic Example

```python
import holidays
from holidays.constants import SCHOOL

# Flemish Community school holidays
be_flemish_schools = holidays.Belgium(subdiv="WBR", categories=SCHOOL, years=2025)

@cubic-dev-ai cubic-dev-ai Bot May 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Belgium school-holidays example uses subdiv="WBR" (French Community) while the comment/variable says Flemish. Use subdiv="VLG" for Flemish Community.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/holiday_categories.md, line 320:

<comment>Belgium school-holidays example uses `subdiv="WBR"` (French Community) while the comment/variable says Flemish. Use `subdiv="VLG"` for Flemish Community.</comment>

<file context>
@@ -299,6 +299,29 @@ for date, name in sorted(germany_catholic.items()):
+from holidays.constants import SCHOOL
+
+# Flemish Community school holidays
+be_flemish_schools = holidays.Belgium(subdiv="WBR", categories=SCHOOL, years=2025)
+for date, name in sorted(be_flemish_schools.items()):
+    print(date, name)
</file context>
Suggested change
be_flemish_schools = holidays.Belgium(subdiv="WBR", categories=SCHOOL, years=2025)
be_flemish_schools = holidays.Belgium(subdiv="VLG", categories=SCHOOL, years=2025)
Fix with Cubic

for date, name in sorted(be_flemish_schools.items()):
Comment on lines +319 to +321

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Example label and subdivision are inconsistent.

Line 319 says Flemish, but Line 320 uses subdiv="WBR" (French Community). Make both refer to the same community.

Suggested doc fix
-# Flemish Community school holidays
-be_flemish_schools = holidays.Belgium(subdiv="WBR", categories=SCHOOL, years=2025)
+# Flemish Community school holidays
+be_flemish_schools = holidays.Belgium(subdiv="VLG", categories=SCHOOL, years=2025)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Flemish Community school holidays
be_flemish_schools = holidays.Belgium(subdiv="WBR", categories=SCHOOL, years=2025)
for date, name in sorted(be_flemish_schools.items()):
# Flemish Community school holidays
be_flemish_schools = holidays.Belgium(subdiv="VLG", categories=SCHOOL, years=2025)
for date, name in sorted(be_flemish_schools.items()):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/holiday_categories.md` around lines 319 - 321, The example label and
subdivision mismatch: the variable be_flemish_schools and heading say "Flemish
Community" but the code uses subdiv="WBR" (Walloon/Brussels); update the subdiv
to the Flemish code (e.g., use subdiv="VLG") or change the heading/variable to
match WBR so both are consistent; adjust the instantiation in
holidays.Belgium(...) where be_flemish_schools and SCHOOL are used to reflect
the chosen community.

print(date, name)
```

### Unofficial Holidays Example

Get unofficial holidays in the United States:
Expand All @@ -307,7 +330,7 @@ Get unofficial holidays in the United States:
import holidays
from holidays.constants import UNOFFICIAL

us_unofficial = holidays.UnitedStates(categories=UNOFFICIAL, years=2024)
us_unofficial = holidays.UnitedStates(categories=UNOFFICIAL, years=2022)
for date, name in sorted(us_unofficial.items()):
print(f"{date}: {name}")
```
Expand Down
310 changes: 307 additions & 3 deletions holidays/countries/belgium.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,62 @@
# Website: https://github.com/vacanza/holidays
# License: MIT (see LICENSE file)

from datetime import date, timedelta
from gettext import gettext as tr

from holidays.constants import BANK, PUBLIC
from holidays.calendars.gregorian import (
JAN,
APR,
JUN,
JUL,
AUG,
SEP,
NOV,
DEC,
MON,
SAT,
_timedelta,
_get_nth_weekday_from,
_get_nth_weekday_of_month,
)
from holidays.constants import BANK, PUBLIC, SCHOOL
from holidays.groups import ChristianHolidays, InternationalHolidays
from holidays.holiday_base import HolidayBase


class Belgium(HolidayBase, ChristianHolidays, InternationalHolidays):
"""Belgium holidays.
"""
Belgium holidays.

References:
* <https://en.wikipedia.org/wiki/Public_holidays_in_Belgium>
* <https://web.archive.org/web/20250331001402/https://www.belgium.be/nl/over_belgie/land/belgie_in_een_notendop/feestdagen>
* <https://nl.wikipedia.org/wiki/Feestdagen_in_België>
* <https://web.archive.org/web/20240816004739/https://www.nbb.be/en/about-national-bank/national-bank-belgium/public-holidays>
* Official education calendars:
* [Flemish Community (Vlaanderen)](https://www.vlaanderen.be/onderwijs-en-vorming/wat-mag-en-moet-op-school/schoolvakanties-vrije-dagen-en-afwezigheden/schoolvakanties)
* [French Community (Fédération Wallonie-Bruxelles)](http://www.enseignement.be/index.php?page=23953)
* [German-speaking Community (Deutschsprachige Gemeinschaft)](https://ostbelgienbildung.be/desktopdefault.aspx/tabid-2212/4397_read-31727/)

Notes:
* Belgium has three school systems with different vacation rules:
* VLG: Flemish Community
* WBR: French Community (Wallonia + Brussels French schools)
* GER: German-speaking Community (Ostbelgien)
* School holiday rules are based on official education calendars.
"""

country = "BE"
default_language = "nl"
supported_categories = (BANK, PUBLIC)
supported_categories = (BANK, PUBLIC, SCHOOL)
supported_languages = ("de", "en_US", "fr", "nl", "uk")

subdivisions = (
"VLG", # Flemish Community.
"WBR", # French Community (Wallonia + Brussels French schools)
"GER", # German-speaking Community.
)

def __init__(self, *args, **kwargs):
ChristianHolidays.__init__(self)
InternationalHolidays.__init__(self)
Expand All @@ -48,10 +82,10 @@
self._add_easter_monday(tr("Paasmaandag"))

# Labor Day.
self._add_labor_day(tr("Dag van de Arbeid"))

Check failure on line 85 in holidays/countries/belgium.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "Dag van de Arbeid" 4 times.

See more on https://sonarcloud.io/project/issues?id=vacanza_python-holidays&issues=AZ38owu3cCN0XUUgzzA4&open=AZ38owu3cCN0XUUgzzA4&pullRequest=3195

# Ascension Day.
self._add_ascension_thursday(tr("O. L. H. Hemelvaart"))

Check failure on line 88 in holidays/countries/belgium.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "O. L. H. Hemelvaart" 4 times.

See more on https://sonarcloud.io/project/issues?id=vacanza_python-holidays&issues=AZ38owu3cCN0XUUgzzA3&open=AZ38owu3cCN0XUUgzzA3&pullRequest=3195

# Whit Sunday.
self._add_whit_sunday(tr("Pinksteren"))
Expand Down Expand Up @@ -84,6 +118,276 @@
# Bank Holiday.
self._add_christmas_day_two(tr("Banksluitingsdag"))

def _add_multiday_holiday(
self, start_date: date, duration_days: int, *, name: str | None = None
) -> set[date]:
"""Override to start adding holidays directly from start_date."""
return super()._add_multiday_holiday(
_timedelta(start_date, -1), duration_days=duration_days, name=name
)
Comment thread
KJhellico marked this conversation as resolved.

def _populate_subdiv_vlg_school_holidays(self):
"""
School holidays for the Flemish Community (Vlaamse Gemeenschap).

Most vacation periods are rule-based and can be calculated
algorithmically, therefore they are implemented here.
"""
Comment on lines +130 to +135

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider deduplicating the shared Christmas-break logic across VLG/WBR/GER.

The Christmas-break block (the December portion + January spillover with (4 - new_year.weekday()) % 7 + 3 duration) is copy-pasted verbatim into all three subdivision methods. Extracting a small private helper (e.g., _add_christmas_school_break(self)) would keep the three methods focused on what differs and avoid future drift.

Also applies to: 218-221, 307-313

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@holidays/countries/belgium.py` around lines 130 - 135, Extract the duplicated
Christmas-break calculation (the December period plus the January spillover
using the `(4 - new_year.weekday()) % 7 + 3` duration) into a single private
helper method (suggested name `_add_christmas_school_break(self, year,
holidays)` or similar) and replace the copy-pasted blocks in the three
subdivision methods for VLG/WBR/GER with calls to that helper; ensure the helper
accepts the year and the holidays collection (or uses the instance state) and
adds the same start/end dates so behavior remains identical.


year = self._year
easter = self._easter_sunday

Comment thread
KJhellico marked this conversation as resolved.
# Christmas Break:
# Starts on the Monday of the week containing Christmas,
# or on the following Monday if Christmas falls on a weekend.
# The break lasts two weeks (14 days) and spans December and January,
# therefore the January portion is added separately.

# Christmas Break.
name = tr("Kerstvakantie")

# December portion of the current Christmas Break.
christmas = self._christmas_day
christmas_start = _get_nth_weekday_from(
1 if self._is_weekend(christmas) else -1, MON, christmas
)
self._add_multiday_holiday(christmas_start, 32 - christmas_start.day, name=name)

# January portion of the previous Christmas Break.
new_year = date(year, JAN, 1)
january_duration = (4 - new_year.weekday()) % 7 + 3
self._add_multiday_holiday(new_year, january_duration, name=name)

# Carnival Break:
# Starts on Carnival Monday, 48 days before Easter.
# The break lasts one week (7 days).

# Carnival Break.
self._add_multiday_holiday(_timedelta(easter, -48), 7, name=tr("Krokusvakantie"))

# Easter Break:
# The start date depends on the date of Easter:
# - If Easter falls in March, the break starts on the Monday after Easter.
# - If Easter falls on or after April 16, the break starts 13 days before Easter.
# - Otherwise, the break starts on the first Monday of April.
# The break normally lasts two weeks (14 days), extended to include Easter Monday
# when necessary.
easter_start = _get_nth_weekday_of_month(1, MON, APR, year)
easter_duration = 14
if easter.month == 3:
easter_start = _timedelta(easter, +1)
elif easter.day >= 16:
easter_start = _timedelta(easter, -13)
easter_duration = 15
# Easter Break.
self._add_multiday_holiday(easter_start, easter_duration, name=tr("Paasvakantie"))
Comment thread
KJhellico marked this conversation as resolved.

# Labor Day.
self._add_labor_day(tr("Dag van de Arbeid"))

# Ascension Day.
self._add_ascension_thursday(tr("O. L. H. Hemelvaart"))

# Friday after Ascension Day.
self._add_holiday_40_days_past_easter(tr("Vrijdag na O. L. H. Hemelvaart"))

# Whit Monday.
self._add_whit_monday(tr("Pinkstermaandag"))
Comment on lines +185 to +195

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Public holidays are being re-emitted inside SCHOOL population methods.

Labor Day, Ascension Day, Friday after Ascension, Whit Monday, Armistice Day, Easter Monday, etc. are public holidays already populated via _populate_public_holidays. Duplicating them inside the SCHOOL subdivision methods creates several problems:

  • A user requesting categories=SCHOOL only gets PUBLIC dates leaking into SCHOOL output.
  • A user requesting categories=(PUBLIC, SCHOOL) gets duplicate-name conflicts on the same dates.
  • The set of "public" days varies inconsistently between VLG/WBR/GER methods (e.g., GER adds Christmas Eve and a "German Community Day"; VLG omits Easter Monday but includes Whit Monday; WBR adds French Community Day on Sep 27).

If the intent is "school-closed days that aren't already public holidays", drop the public-holiday calls and only register break periods + community-specific days (e.g., Sep 27 for WBR, Nov 15 for GER, Dec 24 for GER if school-specific). Otherwise the SCHOOL category will look like a mismatched superset of PUBLIC.

Also applies to: 274-290, 370-389

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@holidays/countries/belgium.py` around lines 185 - 195, The SCHOOL-population
methods are re-adding public holidays (calls to _add_labor_day,
_add_ascension_thursday, _add_holiday_40_days_past_easter, _add_whit_monday,
etc.), causing PUBLIC dates to leak into SCHOOL and duplicate entries; remove
those duplicated _add_* public-holiday calls from the SCHOOL-specific blocks and
instead register only school-specific closures (break periods) and true
community-specific school days (e.g., Sep 27 for WBR, Nov 15 for GER, Dec 24 for
GER if intended) so SCHOOL only contains non-public school closures; ensure you
rely on _populate_public_holidays for public dates and do not re-add them (also
apply the same fix to the other occurrences referenced in the file around the
other ranges).


# Summer Break:
# Fixed period running from July 1 through August 31.
# The break lasts 62 days.

# Summer Break.
self._add_multiday_holiday(date(year, JUL, 1), 62, name=tr("Zomervakantie"))

# Autumn Break:
# Starts on the Monday of the week containing November 1,
# or on the following Monday if November 1 falls on Sunday.
# The break lasts one week (7 days).

nov_1 = date(year, NOV, 1)
autumn_start = _get_nth_weekday_from(1 if self._is_sunday(nov_1) else -1, MON, nov_1)
# Autumn Break.
self._add_multiday_holiday(autumn_start, 7, name=tr("Herfstvakantie"))
Comment thread
KJhellico marked this conversation as resolved.

# Armistice Day.
self._add_remembrance_day(tr("Wapenstilstand"))

def _populate_subdiv_wbr_school_holidays(self):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 2022, the school year schedule in the French-speaking community has changed, which must be considered.

"""
School holidays for the French Community (Wallonie-Bruxelles).
Based on the official compulsory education calendar.
"""

if self.categories != {SCHOOL}:
return
year = self._year
easter = self._easter_sunday

# Christmas Holidays.
# Start on the Monday of the week containing Christmas
# (or the following Monday if Christmas falls on a weekend).
# The holiday period spans late December and continues into January,
# with the January portion added separately.
name = tr("Kerstvakantie")

# Present year's Christmas Holidays.
christmas = self._christmas_day
christmas_start = _get_nth_weekday_from(
1 if self._is_weekend(christmas) else -1, MON, christmas
)
self._add_multiday_holiday(christmas_start, 32 - christmas_start.day, name=name)

# Previous year's Christmas (for January spillover).
new_year = date(year, JAN, 1)
christmas_last_part_duration = (4 - new_year.weekday()) % 7 + 3
self._add_multiday_holiday(new_year, christmas_last_part_duration, name=name)

# Carnival Holidays:
# Start on Carnival Monday (48 days before Easter).
# Duration is two weeks.

self._add_multiday_holiday(_timedelta(easter, days=-48), 14, name=tr("Krokusvakantie"))
Comment on lines +247 to +251

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

WBR Carnival break duration is hardcoded to 14 days regardless of year.

Per your earlier note about the 2022 FWB reform, WBR Carnival was a 1-week break before the 2022–2023 school year and is 2 weeks after. The Autumn block at lines 301–304 already branches on year >= 2022; Carnival needs the same gate, otherwise pre-2022 years will report a 14-day Krokusvakantie that never existed.

🛠️ Suggested fix
-        self._add_multiday_holiday(_timedelta(easter, days=-48), 14, name=tr("Krokusvakantie"))
+        # Carnival Holidays: 1 week pre-2022 reform, 2 weeks afterwards.
+        carnival_duration = 14 if year >= 2022 else 7
+        self._add_multiday_holiday(
+            _timedelta(easter, -48), carnival_duration, name=tr("Krokusvakantie")
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@holidays/countries/belgium.py` around lines 247 - 251, The Carnival
(Krokusvakantie) holiday is always added as 14 days via
self._add_multiday_holiday(_timedelta(easter, days=-48), 14,
name=tr("Krokusvakantie")) but the duration changed after the 2022 reform;
update the logic around the call in the relevant function to branch on the year
(use the existing year variable) and pass 7 days for years < 2022 and 14 days
for years >= 2022 (keep use of _timedelta(easter, days=-48) and
tr("Krokusvakantie") unchanged so only the duration argument is conditional).


# Spring Holidays (WBR, post-2022):
# Start on the last Monday of April.
# If this falls before April 25, shift to the following Monday (in May).

apr_30 = date(year, APR, 30)

spring_start = _get_nth_weekday_from(-1, MON, apr_30)

if spring_start.day < 25:
spring_start += timedelta(days=7)
self._add_multiday_holiday(spring_start, 14, name=tr("Lentevakantie"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff

WBR Spring break and pre/post-2022 Autumn rules conflict with the project's "simplest rule with fewest exceptions" guidance.

spring_start += timedelta(days=7) on line 262 plus the manual last-Monday computation on lines 298–300 mix two timedelta styles in the same method. Combined with the year branch on lines 301–304 and the missing year branch on Carnival, the WBR rules are difficult to follow. Consider extracting clear constants (e.g., WBR_REFORM_YEAR = 2022) and computing all break starts via _get_nth_weekday_from / _get_nth_weekday_of_month to keep one consistent calculation idiom.

Also applies to: 302-304

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@holidays/countries/belgium.py` at line 263, The spring/autumn/WBR rules mix
timedelta adjustments and manual weekday math, and miss a year branch for
Carnival; introduce a constant (e.g., WBR_REFORM_YEAR = 2022) and refactor the
calculations to use the existing helper utilities (like _get_nth_weekday_from or
_get_nth_weekday_of_month) for all break start dates (spring_start,
autumn_start, carnival_start) instead of ad-hoc timedelta/last-Monday
computations, add the missing year-dependent branch for Carnival matching the
reform rule, and update calls to _add_multiday_holiday to use those computed
starts so the method uses one consistent idiom and the reform-year constant
governs branching.


# Summer holidays.
summer_start = _get_nth_weekday_of_month(1, SAT, JUL, year)
# If the first Saturday is July 1 (too early), shift to the next Saturday.
if summer_start.day == 1:
summer_start += timedelta(days=7)
summer_end = _get_nth_weekday_of_month(4, MON, AUG, year)
duration = (summer_end - summer_start).days
self._add_multiday_holiday(summer_start, duration, name=tr("Zomervakantie"))

# Armistice Day.
self._add_remembrance_day(tr("Wapenstilstand"))

# Labour Day.
self._add_labor_day(tr("Dag van de Arbeid"))

# French Community Day.
self._add_holiday(tr("Feestdag van de Franse Gemeenschap"), date(year, SEP, 27))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Use the existing _add_holiday_* helpers instead of constructing dates manually.

self._add_holiday(tr("..."), date(year, SEP, 27)) can be replaced with self._add_holiday_sep_27(tr("...")), and likewise _add_holiday_nov_15 and _add_holiday_dec_24. The helper form is the project's idiomatic style and avoids the manual date(year, ...) boilerplate.

♻️ Suggested fix
-        self._add_holiday(tr("Feestdag van de Franse Gemeenschap"), date(year, SEP, 27))
+        self._add_holiday_sep_27(tr("Feestdag van de Franse Gemeenschap"))
-        self._add_holiday(tr("Feestdag van de Duitstalige Gemeenschap"), date(year, NOV, 15))
+        self._add_holiday_nov_15(tr("Feestdag van de Duitstalige Gemeenschap"))
-        self._add_holiday(tr("Heiligavond"), date(year, DEC, 24))
+        self._add_holiday_dec_24(tr("Heiligavond"))

Also applies to: 377-377, 389-389

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@holidays/countries/belgium.py` at line 281, Replace manual date constructions
that call self._add_holiday(tr("..."), date(year, SEP, 27/ NOV, 15/ DEC, 24))
with the project's helper methods: use self._add_holiday_sep_27(tr("...")),
self._add_holiday_nov_15(tr("...")), and self._add_holiday_dec_24(tr("..."))
respectively; locate the three occurrences where date(year, SEP, 27), date(year,
NOV, 15), and date(year, DEC, 24) are passed into self._add_holiday and swap
them to the corresponding _add_holiday_* helper calls to follow the idiomatic
style and remove manual date boilerplate.


# Easter Monday.
self._add_easter_monday(tr("Paasmaandag"))

# Ascension Day.
self._add_ascension_thursday(tr("O. L. H. Hemelvaart"))

# Whit Monday.
self._add_whit_monday(tr("Pinkstermaandag"))

# Autumn Holidays:
# - Start → second last Monday of October.
# - Before the 2022-2023 school year → duration was 1 week.
# - From the 2022-2023 school year → duration is 2 weeks.

# Autumn Holidays.
nov_first = date(year, 11, 1)
last_monday = nov_first - timedelta(days=(nov_first.weekday() - MON) % 7)
autumn_start = last_monday - timedelta(days=7)
if year >= 2022:
self._add_multiday_holiday(autumn_start, 14, name=tr("Herfstvakantie"))
else:
self._add_multiday_holiday(autumn_start, 7, name=tr("Herfstvakantie"))
Comment on lines +292 to +304

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Inline the year branch and add a # Autumn Holidays. rule comment block — match the VLG style.

The rest of the file uses a # <Period>: <rule> description block followed by # <Period>. then the call. Here the rule comment is present but the calculation reads less linearly than VLG's autumn block. Consolidating the if/else into a single _add_multiday_holiday call also helps:

-        nov_first = date(year, 11, 1)
-        last_monday = nov_first - timedelta(days=(nov_first.weekday() - MON) % 7)
-        autumn_start = last_monday - timedelta(days=7)
-        if year >= 2022:
-            self._add_multiday_holiday(autumn_start, 14, name=tr("Herfstvakantie"))
-        else:
-            self._add_multiday_holiday(autumn_start, 7, name=tr("Herfstvakantie"))
+        autumn_start = _get_nth_weekday_from(-2, MON, date(year, NOV, 1))
+        # Autumn Holidays.
+        self._add_multiday_holiday(
+            autumn_start, 14 if year >= 2022 else 7, name=tr("Herfstvakantie")
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@holidays/countries/belgium.py` around lines 292 - 304, Inline the year-based
branch and add the VLG-style rule comment block for the Autumn Holidays: compute
nov_first, last_monday and autumn_start as currently done, then call
self._add_multiday_holiday once with duration = 14 if year >= 2022 else 7; keep
the holiday name tr("Herfstvakantie"). Also add the two-line comment pattern
before the code: a "# Autumn Holidays: <rule>" line describing the rule and a
following "# Autumn Holidays." line, matching the style used elsewhere in the
file and using the existing symbols nov_first, last_monday, autumn_start and the
call to _add_multiday_holiday.


def _populate_subdiv_ger_school_holidays(self):
"""
School holidays for the German-speaking Community (Deutschsprachige Gemeinschaft).

Based on official education calendar structure.
Most vacation periods follow patterns similar to other Belgian communities,
with some variations in timing and duration.
"""

if self.categories != {SCHOOL}:
return
year = self._year
easter = self._easter_sunday

# Christmas Holidays.
# Start on the Monday of the week containing Christmas
# (or the following Monday if Christmas falls on a weekend).
# The holiday period spans late December and continues into January,
# with the January portion added separately.
name = tr("Kerstvakantie")

# Present year's Christmas Holidays.
christmas = self._christmas_day
christmas_start = _get_nth_weekday_from(
1 if self._is_weekend(christmas) else -1, MON, christmas
)
self._add_multiday_holiday(christmas_start, 32 - christmas_start.day, name=name)

# Previous year's Christmas (for January spillover).
new_year = date(year, JAN, 1)
christmas_last_part_duration = (4 - new_year.weekday()) % 7 + 3
self._add_multiday_holiday(new_year, christmas_last_part_duration, name=name)

# Carnival Holidays.
# Start on Carnival Monday, which occurs 48 days before Easter.
# The vacation lasts for one week.
self._add_multiday_holiday(_timedelta(easter, days=-48), 7, name=tr("Krokusvakantie"))

# Easter Holidays.
# Usually start on the first Monday of April.
# If Easter is very late (on or after April 18), holidays start on the Monday after Easter.
# Duration is approximately two weeks (12 days).
april_1 = date(year, APR, 1)
first_monday_april = _get_nth_weekday_from(1, MON, april_1)

# If Easter is very late → shift after Easter
if easter.month == 4 and easter.day >= 18:
easter_start = _timedelta(easter, days=1)
else:
easter_start = first_monday_april

# Duration is approximately two weeks (12 calendar days).
self._add_multiday_holiday(easter_start, 12, name=tr("Paasvakantie"))

# Summer holidays.
self._add_multiday_holiday(date(year, JUN, 30), 63, name=tr("Zomervakantie"))

# Autumn Holidays.
# Start on the Monday of the week containing November 1.
# Duration is one week in the German-speaking Community calendar.
nov_1 = date(year, NOV, 1)
autumn_start = _get_nth_weekday_from(1 if self._is_sunday(nov_1) else -1, MON, nov_1)
self._add_multiday_holiday(autumn_start, 7, name=tr("Herfstvakantie"))

# Armistice Day.
self._add_remembrance_day(tr("Wapenstilstand"))

# Labour Day.
self._add_labor_day(tr("Dag van de Arbeid"))

# German Community Day.
self._add_holiday(tr("Feestdag van de Duitstalige Gemeenschap"), date(year, NOV, 15))

# Easter Monday.
self._add_easter_monday(tr("Paasmaandag"))

# Ascension Day.
self._add_ascension_thursday(tr("O. L. H. Hemelvaart"))

# Whit Monday.
self._add_whit_monday(tr("Pinkstermaandag"))

# Christmas Eve.
self._add_holiday(tr("Heiligavond"), date(year, DEC, 24))
Comment on lines +388 to +389

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Christmas Eve is already inside the GER Christmas break.

Lines 327–337 register the Christmas break which spans the week of Dec 25 (and thus includes Dec 24 in most years). Re-adding tr("Heiligavond") on Dec 24 will either collide with the existing break entry or shadow it depending on insertion order. If Dec 24 is meant to be a distinct named day for GER, add it before the break and document the override; otherwise drop it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@holidays/countries/belgium.py` around lines 388 - 389, The explicit addition
of Heiligavond via self._add_holiday(tr("Heiligavond"), date(year, DEC, 24))
conflicts with the previously added Christmas break entry (the block that
registers the Christmas break spanning Dec 25 and surrounding days); either
remove this Heiligavond line to avoid collision, or if you intend Dec 24 to be a
distinct named day for Belgium, move the self._add_holiday(tr("Heiligavond"),
date(year, DEC, 24)) call so it executes before the Christmas-break registration
and add a comment documenting that it intentionally overrides/shadows the break
entry for Dec 24.



class BE(Belgium):
pass
Expand Down
Loading