New South Wales public school terms, school holidays and school development days, from the rules the Department of Education's calendars follow.
The Department publishes each year's calendar a few years ahead, and publishes it as dates, not rules. These rules reproduce every calendar it has published, 2016 to 2030, in both divisions, and project the years after:
Term 1 ends before Easter or in the week of 7–13 April — on the day before Good Friday when Good Friday falls 31 March–13 April, so Easter opens the autumn holidays, and otherwise on the Friday that falls 7–13 April.
The autumn, winter and spring holidays are two weeks — each runs from the Monday after a term's last day, and the next term starts on the Monday two weeks later, or on the next school day when that Monday is a public holiday.
Term 3 is ten weeks — Monday of its first week to Friday of its tenth.
Term 2 runs to Term 3 — up to 2025 Term 2 is ten weeks. From 2026 Term 3 starts on the Monday on or after 18 July, so Term 2 is ten weeks or eleven.
Term 4 ends in the week before Christmas — up to 2025 on the Friday that falls 17–23 December, or on that week's Tuesday when the Friday is the 22nd or 23rd; from 2026 on the Thursday that falls 17–23 December, or on that week's Monday when the Thursday is the 22nd or 23rd.
Term 1 starts after Australia Day — up to 2021 on the school day after Australia Day; from 2022 six weeks after the previous Term 4 ended, on the same weekday, unless the year would then have fewer than 199 school days, when it starts on the school day after Australia Day.
The Western division starts a week later — its Term 1 starts seven days after the Eastern division's.
A school day is a weekday that is not one of New South Wales' public holidays,
as Tempo.Holidays.holidays/2 gives them, and school development days are
school days. terms/2, holidays/2 and development_days/2 return interval
sets, so they compose with the rest of Tempo.
Example
{:ok, terms} = NSW.terms(~o"2027")
{:ok, holidays} = NSW.holidays(~o"2027")
{:ok, next_holidays} = Tempo.members_overlapping(holidays, ~o"2027-07")"The NSW school terms of 2027, the holidays between them, and the holidays that fall in July."
Summary
Types
A school division: :eastern, most of the state, or :western, the schools
in the far west, whose Term 1 starts a week later.
A school year: a year from 2016, as an integer or a Tempo value naming it.
Functions
Returns a year's school development days.
Returns a year's four school holidays.
Returns a year's four school terms.
Types
@type division() :: :eastern | :western
A school division: :eastern, most of the state, or :western, the schools
in the far west, whose Term 1 starts a week later.
@type year() :: pos_integer() | Tempo.t()
A school year: a year from 2016, as an integer or a Tempo value naming it.
Functions
Returns a year's school development days.
Staff attend on a school development day and students do not. The Department has published them since 2023: the first two school days of Term 1, the first of Terms 2 and 3, and the last two of Term 4 in 2023 and 2024; from 2025 the first four school days of Term 1, the first two of Term 2, and the first of Terms 3 and 4. Each day is tagged with its term's number.
Arguments
yearis a year from 2023, as an integer or aTempo.t/0naming it.
Options
:divisionis:easternor:western, as forterms/2: the Western division's Term 1 development days are the first days of its own Term 1.
Returns
{:ok, development_days}, a set (aTempo.t/0) of the days.{:error, reason}as forterms/2, or{:unpublished_development_days, year}for a year before 2023.
Examples
iex> {:ok, days} = Tempo.Holidays.SchoolTerms.NSW.development_days(~o"2027")
iex> days |> Tempo.IntervalSet.members() |> Enum.map(&Tempo.to_iso8601!/1)
["2027Y1M28D", "2027Y1M29D", "2027Y2M1D", "2027Y2M2D", "2027Y4M27D", "2027Y4M28D",
"2027Y7M19D", "2027Y10M11D"]
Returns a year's four school holidays.
The holidays are the days between the terms: the autumn, winter and spring
holidays after Terms 1, 2 and 3, and the summer holidays after Term 4, which
run into the next year until its Term 1 starts. Each holiday takes in the
weekends either side, and is tagged %{holiday: :autumn}, :winter,
:spring or :summer.
Arguments
yearis a year from 2016, as forterms/2.
Options
:divisionis:easternor:western, as forterms/2: the Western division's summer holidays run a week longer.
Returns
Examples
iex> {:ok, holidays} = Tempo.Holidays.SchoolTerms.NSW.holidays(~o"2027")
iex> holidays |> Tempo.IntervalSet.members() |> Enum.map(&Tempo.to_iso8601!/1)
["2027Y4M10D/26D", "2027Y7M3D/18D", "2027Y9M25D/10M10D", "2027Y12M21D/2028Y1M30D"]
Returns a year's four school terms.
Each term runs from its first day to its last, school development days
included, and is tagged with its number: %{term: 1} to %{term: 4}.
Arguments
yearis a year from 2016, the first the rules were checked against: an integer or aTempo.t/0naming the year,~o"2027".
Options
:divisionis:eastern, the default, or:westernfor the schools in the far west, whose Term 1 starts a week later.
Returns
{:ok, terms}, a set (aTempo.t/0) of the four terms.{:error, reason}—{:invalid_year, year},{:invalid_division, division}or{:invalid_option, options}.
Examples
iex> {:ok, terms} = Tempo.Holidays.SchoolTerms.NSW.terms(~o"2027")
iex> terms |> Tempo.IntervalSet.members() |> Enum.map(&Tempo.to_iso8601!/1)
["2027Y1M28D/4M9D", "2027Y4M27D/7M2D", "2027Y7M19D/9M24D", "2027Y10M11D/12M20D"]
iex> {:ok, terms} = Tempo.Holidays.SchoolTerms.NSW.terms(2027, division: :western)
iex> terms |> Tempo.IntervalSet.first() |> Tempo.to_iso8601!()
"2027Y2M4D/4M9D"