{
  "$schema": "../cases.schema.json",
  "format": 1,
  "domain": "date",
  "title": {
    "en": "Dates and holidays",
    "pt-BR": "Datas e feriados"
  },
  "functions": [
    {
      "id": "date.addBusinessDays",
      "level": "extended",
      "summary": "Adds a number of Brazilian business days (dias úteis) to a date.",
      "description": "Adds a number of Brazilian business days (dias úteis) to a date. It walks one calendar day at a time and counts only the days `date.isBusinessDay` accepts with the same `options`.\n\n- Returns a new date and keeps the time of day. The function never changes the input. When the result day does not have that time (a daylight saving jump), the result is the nearest instant of that day.\n- An `amount` of 0 returns the same date, even on a non-business day. A negative `amount` walks backwards.\n- `options.includeOptional` (default true) counts the optional holidays (Carnaval Monday and Tuesday, Corpus Christi) as non-business days. With false, only `national` and `state` holidays count, so Corpus Christi still counts in DF, in MA from 2024 and in RJ from 2026, where it is a state holiday.\n- `options.includeSaturday` (default false) counts Saturday as a business day, the labor law count of the payroll deadline (CLT art. 459 § 1º, read through IN MTP nº 2/2021, art. 14, I). Sunday and holidays stay excluded, including a holiday on a Saturday (Finados 2024-11-02, Independência 2024-09-07).\n- `includeSaturday` does not cover municipal holidays, which the IN also excludes. An exact count for a municipality has to remove them separately. The option name does not promise \"CLT\" for that reason.\n- A truthy value that is not a boolean (for example `\"false\"`) turns `includeSaturday` or `includeOptional` on.\n- `options.stateCode` is read ignoring case and surrounding whitespace, as in every state util: `\"sp\"` and `\" SP \"` add the holidays of São Paulo. Only an omitted (`undefined`) `stateCode` means national holidays only.\n- A `stateCode` that is present and is not a state code (`\"XX\"`, `\"\"`, `\"__proto__\"`, a number, `null`, an object) is rejected: the function returns `null` without looking at the date. 2.4.0 silently fell back to the national holidays for an unknown or lowercase code, so `\"sp\"` counted 9 July as a business day in São Paulo.\n- Returns `null` for an invalid date, an `amount` that is not a finite integer, or a start or result outside the years 1900 to 2099.\n- The walk always ends. 2.4.0 could loop forever in time zones where a local day does not exist (Pacific/Apia and Pacific/Fakaofo on 2011-12-30, Pacific/Kiritimati and Pacific/Enderbury on 1994-12-31, Pacific/Kwajalein on 1993-08-21); the walk now skips that day. The half-hour shift of Australia/Lord_Howe was fixed too. Other results are unchanged.\n\nRecipes (no dedicated helper exists):\n\n- Next business day: `addBusinessDays(d, 1)`.\n- N-th business day of a month: `addBusinessDays(new Date(y, m, 0), n)`, starting from the last day of the previous month. When `n` is larger than the month's business days, the result falls in the next month; check its month.\n- Last business day of a month: `subBusinessDays(new Date(y, m + 1, 1), 1)`, starting from the first day of the next month.\n- Edges: the n-th business day of January 1900 and the last business day of December 2099 return `null`, because the starting day is outside 1900 to 2099.\n- With `{ includeSaturday: true }` the same recipe gives the labor law \"quinto dia útil\": `addBusinessDays(new Date(2024, 2, 0), 5, { includeSaturday: true })` is Wednesday 2024-03-06, while the banking count without the option is Thursday 2024-03-07.",
      "params": [
        {
          "name": "date",
          "type": "date"
        },
        {
          "name": "amount",
          "type": "number"
        },
        {
          "name": "options",
          "type": "BusinessDayOptions",
          "optional": true
        }
      ],
      "returns": "date?",
      "cases": []
    },
    {
      "id": "date.convertToWords",
      "level": "extended",
      "summary": "Formats a date as its Brazilian Portuguese \"por extenso\" text.",
      "description": "Writes a date in Brazilian Portuguese words (\"por extenso\"), such as \"primeiro de janeiro de dois mil e vinte e quatro\".\n\n- `value` is a date (its local calendar date) or a string `dd/mm/yyyy` or ISO `yyyy-mm-dd`.\n- `options.style` (default `\"full\"`) spells out the day, the month and the year (`\"dois de março de dois mil e vinte e quatro\"`). `\"month\"` spells out only the month and leaves the day and the year as digits (`\"2 de março de 2024\"`), with day 1 as `1º` (`\"1º de janeiro de 2024\"`). Any other value is ignored and `\"full\"` is used.\n- `options.weekday` (default false) puts the weekday name in lowercase and a comma in front (`\"sábado, dois de março de dois mil e vinte e quatro\"`). The weekday comes from the resolved calendar date: the local date of a date value, or the parsed date of a string. It combines with either style.\n- `style` and `weekday` are read strictly: only `\"month\"` and only `true` change the output. `\"true\"` or `1` for `weekday` do nothing.\n- Day 1 is \"primeiro\" in the `full` style.\n- In the `full` style the year is written as `number.convertToWords` writes it (`1999` is \"mil novecentos e noventa e nove\", `2000` is \"dois mil\"). The result is always lowercase.\n- February 29th is accepted only on leap years of the proleptic Gregorian calendar (divisible by 4, except centuries not divisible by 400). A string must match `dd/mm/yyyy` or `yyyy-mm-dd` exactly, with no other characters around it.\n- Pending decision (findings §1b): the reference (JS) writes all lowercase and parses ISO strings. Go and Ruby capitalize and do not parse ISO strings.\n- Pending decision (findings §2 #9): the reference (JS) returns an empty string for an invalid date, a malformed string, a day or month that does not exist, or a year before 1. Other libraries return `null`.",
      "params": [
        {
          "name": "value",
          "type": "date | string"
        },
        {
          "name": "options",
          "type": "ConvertDateToWordsOptions",
          "optional": true
        }
      ],
      "returns": "string",
      "cases": [
        {
          "id": "date.convertToWords#first-of-month",
          "args": [
            "01/01/2024"
          ],
          "expect": {
            "returns": "primeiro de janeiro de dois mil e vinte e quatro"
          }
        },
        {
          "id": "date.convertToWords#[\"02/01/2024\"]",
          "args": [
            "02/01/2024"
          ],
          "expect": {
            "returns": "dois de janeiro de dois mil e vinte e quatro"
          }
        },
        {
          "id": "date.convertToWords#[\"25/12/2024\"]",
          "args": [
            "25/12/2024"
          ],
          "expect": {
            "returns": "vinte e cinco de dezembro de dois mil e vinte e quatro"
          }
        },
        {
          "id": "date.convertToWords#iso-string",
          "args": [
            "2024-12-25"
          ],
          "expect": {
            "returns": "vinte e cinco de dezembro de dois mil e vinte e quatro"
          }
        },
        {
          "id": "date.convertToWords#leap-day",
          "args": [
            "29/02/2000"
          ],
          "expect": {
            "returns": "vinte e nove de fevereiro de dois mil"
          }
        },
        {
          "id": "date.convertToWords#not-a-leap-year",
          "args": [
            "29/02/2023"
          ],
          "expect": {
            "returns": ""
          },
          "note": "invalid dates: the reference returns an empty string (asserted by its tests); some libs return null/None"
        },
        {
          "id": "date.convertToWords#day-out-of-range",
          "args": [
            "31/04/2024"
          ],
          "expect": {
            "returns": ""
          }
        },
        {
          "id": "date.convertToWords#garbage",
          "args": [
            "not a date"
          ],
          "expect": {
            "returns": ""
          }
        },
        {
          "id": "date.convertToWords#empty",
          "args": [
            ""
          ],
          "expect": {
            "returns": ""
          }
        },
        {
          "id": "date.convertToWords#[\"15/13/2024\"]",
          "args": [
            "15/13/2024"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: should reject an out of range month"
        },
        {
          "id": "date.convertToWords#[\"15/00/2024\"]",
          "args": [
            "15/00/2024"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: should reject an out of range month"
        },
        {
          "id": "date.convertToWords#[\"00/01/2024\"]",
          "args": [
            "00/01/2024"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: should reject an out of range day"
        },
        {
          "id": "date.convertToWords#[\"32/01/2024\"]",
          "args": [
            "32/01/2024"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: should reject an out of range day"
        },
        {
          "id": "date.convertToWords#[\"02/03/2024\"]",
          "args": [
            "02/03/2024"
          ],
          "expect": {
            "returns": "dois de março de dois mil e vinte e quatro"
          },
          "note": "JavaScript's own test: letter case should always keep the result lowercase"
        },
        {
          "id": "date.convertToWords#[\"02/03/2024\",{\"weekday\":true}]",
          "args": [
            "02/03/2024",
            {
              "weekday": true
            }
          ],
          "expect": {
            "returns": "sábado, dois de março de dois mil e vinte e quatro"
          },
          "note": "JavaScript's own test: letter case should always keep the result lowercase"
        },
        {
          "id": "date.convertToWords#[\"02/03/2024\",{\"style\":\"month\"}]",
          "args": [
            "02/03/2024",
            {
              "style": "month"
            }
          ],
          "expect": {
            "returns": "2 de março de 2024"
          },
          "note": "JavaScript's own test: style option should write only the month name and leave day/year as digits for 'month'"
        },
        {
          "id": "date.convertToWords#[\"01/01/2024\",{\"style\":\"full\"}]",
          "args": [
            "01/01/2024",
            {
              "style": "full"
            }
          ],
          "expect": {
            "returns": "primeiro de janeiro de dois mil e vinte e quatro"
          },
          "note": "JavaScript's own test: style option should write day 1 as 'primeiro' in 'full' style and as '1º' in 'month' style"
        },
        {
          "id": "date.convertToWords#[\"01/01/2024\",{\"style\":\"month\"}]",
          "args": [
            "01/01/2024",
            {
              "style": "month"
            }
          ],
          "expect": {
            "returns": "1º de janeiro de 2024"
          },
          "note": "JavaScript's own test: style option should write day 1 as 'primeiro' in 'full' style and as '1º' in 'month' style"
        },
        {
          "id": "date.convertToWords#[\"01/01/2024\",{\"weekday\":true,\"style\":\"month\"}]",
          "args": [
            "01/01/2024",
            {
              "weekday": true,
              "style": "month"
            }
          ],
          "expect": {
            "returns": "segunda-feira, 1º de janeiro de 2024"
          },
          "note": "JavaScript's own test: weekday option should combine with 'month' style"
        },
        {
          "id": "date.convertToWords#[\"2024/01/01\"]",
          "args": [
            "2024/01/01"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: invalid input should return '' for a malformed string"
        },
        {
          "id": "date.convertToWords#[\"01-01-2024\"]",
          "args": [
            "01-01-2024"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: invalid input should return '' for a malformed string"
        },
        {
          "id": "date.convertToWords#[\"01/01/2024xyz\"]",
          "args": [
            "01/01/2024xyz"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: invalid input should reject a 'dd/mm/yyyy' match that is not anchored to the whole string"
        },
        {
          "id": "date.convertToWords#[\"xyz01/01/2024\"]",
          "args": [
            "xyz01/01/2024"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: invalid input should reject a 'dd/mm/yyyy' match that is not anchored to the whole string"
        },
        {
          "id": "date.convertToWords#[\"2024-01-02xyz\"]",
          "args": [
            "2024-01-02xyz"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: invalid input should reject an ISO 'yyyy-mm-dd' match that is not anchored to the whole string"
        },
        {
          "id": "date.convertToWords#[\"xyz2024-01-02\"]",
          "args": [
            "xyz2024-01-02"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: invalid input should reject an ISO 'yyyy-mm-dd' match that is not anchored to the whole string"
        },
        {
          "id": "date.convertToWords#[\"01/01/0000\"]",
          "args": [
            "01/01/0000"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: years outside the calendar should return '' for year zero, which has no year to write out"
        },
        {
          "id": "date.convertToWords#[\"0000-01-01\"]",
          "args": [
            "0000-01-01"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: years outside the calendar should return '' for year zero, which has no year to write out"
        },
        {
          "id": "date.convertToWords#[\"01/01/0001\"]",
          "args": [
            "01/01/0001"
          ],
          "expect": {
            "returns": "primeiro de janeiro de um"
          },
          "note": "JavaScript's own test: years outside the calendar should accept year 1, the earliest year with a year to write out"
        },
        {
          "id": "date.convertToWords#[\"29/02/1600\"]",
          "args": [
            "29/02/1600"
          ],
          "expect": {
            "returns": "vinte e nove de fevereiro de mil e seiscentos"
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should accept February 29th on a year divisible by 400"
        },
        {
          "id": "date.convertToWords#[\"29/02/1900\"]",
          "args": [
            "29/02/1900"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should reject February 29th on a century that is not divisible by 400"
        },
        {
          "id": "date.convertToWords#[\"29/02/2100\"]",
          "args": [
            "29/02/2100"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should reject February 29th on a century that is not divisible by 400"
        },
        {
          "id": "date.convertToWords#[\"29/02/1800\"]",
          "args": [
            "29/02/1800"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should reject February 29th on a century that is not divisible by 400"
        },
        {
          "id": "date.convertToWords#[\"29/02/0004\"]",
          "args": [
            "29/02/0004"
          ],
          "expect": {
            "returns": "vinte e nove de fevereiro de quatro"
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should accept February 29th on a year of the first century divisible by 4"
        },
        {
          "id": "date.convertToWords#[\"29/02/0096\"]",
          "args": [
            "29/02/0096"
          ],
          "expect": {
            "returns": "vinte e nove de fevereiro de noventa e seis"
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should accept February 29th on a year of the first century divisible by 4"
        },
        {
          "id": "date.convertToWords#[\"29/02/0003\"]",
          "args": [
            "29/02/0003"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should reject February 29th on a year of the first century not divisible by 4"
        },
        {
          "id": "date.convertToWords#[\"29/02/0100\"]",
          "args": [
            "29/02/0100"
          ],
          "expect": {
            "returns": ""
          },
          "note": "JavaScript's own test: leap years of the proleptic Gregorian calendar should reject February 29th on a year of the first century not divisible by 4"
        },
        {
          "id": "date.convertToWords#year-1999",
          "args": [
            "10/05/1999"
          ],
          "expect": {
            "returns": "dez de maio de mil novecentos e noventa e nove"
          },
          "note": "JavaScript docs example"
        }
      ]
    },
    {
      "id": "date.differenceInBusinessDays",
      "level": "extended",
      "summary": "Counts the number of Brazilian business days (dias úteis) between two dates.",
      "description": "Counts the Brazilian business days between two dates.\n\n- Counts `earlierDate` when it is a business day, and every business day strictly between the two. It never counts `laterDate`. The time of day is ignored.\n- The result is negative when `laterDate` is before `earlierDate`, and 0 on the same calendar day.\n- `options` as in `date.addBusinessDays`: `includeOptional`, `includeSaturday` and `stateCode`. With `{ includeSaturday: true }`, 2024-01-01 to 2024-01-08 gives 5 (1 January is a holiday, Sunday is excluded).\n- Returns `null` when either date is invalid or outside the years 1900 to 2099, and when `options.stateCode` is present and is not a state code (2.4.0 fell back to national holidays).",
      "params": [
        {
          "name": "laterDate",
          "type": "date"
        },
        {
          "name": "earlierDate",
          "type": "date"
        },
        {
          "name": "options",
          "type": "BusinessDayOptions",
          "optional": true
        }
      ],
      "returns": "number?",
      "cases": []
    },
    {
      "id": "date.getHolidays",
      "level": "extended",
      "summary": "Gets all Brazilian holidays for a year.",
      "description": "Returns the Brazilian holidays of a year, sorted by date: the national ones, plus those of one state when `stateCode` is given.\n\n- `options` is `{ year, stateCode? }`. JavaScript also accepts a bare year, `getHolidays(2024)`, for the national holidays.\n- Each holiday has a name, a date and a `type`: `national`, `state`, `optional` (ponto facultativo) or `religious` (Páscoa, listed for convenience; no norm declares it).\n- `stateCode` is read ignoring case and surrounding whitespace, as in every state util. Only an omitted (`undefined`) `stateCode` means national holidays only.\n- A `stateCode` that is present and is not a state code (`\"XX\"`, `\"\"`, `\"__proto__\"`, a number, `null`, an object) returns an empty list. 2.4.0 returned the national holidays for it, so `{ year: 2024, stateCode: \"sp\" }` left out the São Paulo holidays.\n- Returns an empty list when `year` is not an integer from 1900 to 2099.\n- Each holiday appears only in the years its norm was in force:\n  - Fixed national holidays appear only in the years a federal norm declared them. Finados appears up to 1948 and from 2003 on, not from 1949 to 2002 (2.4.0 listed it every year). Nossa Senhora Aparecida appears from 1980. Dia da Consciência Negra (20 November) is national from 2024.\n  - Natal appears from 1922, Dia do trabalhador from 1925, and Tiradentes up to 1930, from 1933 to 1948 and from 1951. Lei nº 662/1949 left Finados out of the national holidays Decreto-lei nº 486/1938 listed, and Lei nº 10.607/2002 put it back. The other national festivals of the first republican calendar (24 February, 3 May, 13 May, 14 July and 12 October) are listed up to 1930, and 3 May (1936 to 1938), 16 July and 12 October (1936 and 1937) again under Lei nº 108/1935.\n  - State holidays appear from the year their law took effect, and up to the year it was revoked.\n- Sexta-feira Santa is `national` every year. Carnaval Monday and Tuesday and Corpus Christi are `optional`, the pontos facultativos of the federal calendar (2.4.0 did not list the Monday).\n- The `optional` entries are the whole-day pontos facultativos of the federal calendar (Portarias MGI nº 8.617/2023, 9.783/2024 and 11.460/2025, for 2024 to 2026): Carnaval Monday and Tuesday and Corpus Christi, the same three days the financial market skips (Resolução CMN nº 4.880/2020), plus the ones a state norm declares (AM's 8 December from 1999, PE's 6 March of 2008 and 2009). The partial ones are left out: Quarta-feira de Cinzas (until 14h), 28 October (Dia do Servidor Público) and the afternoons of 24 and 31 December.\n- The first round of the elections is a `national` holiday: the first Sunday of October in even years from 1998 on (15 November in 2020), under art. 380 of the Código Eleitoral. The second round is not listed.\n- Before 1998, Lei nº 1.266/1950 made the day of the general elections a national holiday, so the ones held on a weekday are listed too: 3 October of 1955 and 1958 (`Eleições gerais`) and of 1990 and 1994 (`Eleições (primeiro turno)`). 3 October 1960 and the municipal election of 3 October 1996 are not listed. Being a Sunday, the election day never changes a business day count.\n- A state entry with the same name and date as a national one replaces it. Corpus Christi is typed `state` in DF, in MA from 2024 and in RJ from 2026, and stays an optional federal ponto facultativo elsewhere. The Carnaval Tuesday is a state holiday in RJ from 2009.\n- Two observance shifts move a state date. Alagoas' 30 November goes back to Monday when it falls on a Tuesday and on to Friday when it falls on a Thursday (from 2014, Lei AL nº 7.530/2013). Santa Catarina's 11 August (from 2005) and 25 November (from 1999) each move to the following Sunday when they fall Monday to Saturday. Pernambuco's data magna falls on the first Sunday of March from 2010 to 2017 and on 6 March from 2018.\n- A state law the STF struck down has no entry in any year: Rondônia's 18 June (ADI 3940) and Amapá's 25 July (ADI 4820).\n- Goiás lists 26/07, 24/10 and 28/10 as the feriados estaduais of the state servants' statute, from 1986, and 2 November as a Goiás holiday from 1986 to 2002, the years Finados was not national. Alagoas' 16/09 is a `state` holiday from 2011 (2.4.0 typed it `optional` up to 2023).\n- Changes in 2.5.0, each from the state norm cited in the JavaScript source:\n  - RJ: Corpus Christi from 2026 (Lei RJ nº 11.002/2025, upheld by the STF in ADI 7898, final on 13/08/2026). 2.4.0 typed it `optional`, as in every other state.\n  - AL: 20/11 from 1995 to 2023; 30/11 from 2014 (moved to Monday when it falls on a Tuesday and to Friday when it falls on a Thursday).\n  - AC: 20/01 from 2017. AP: 20/11 from 2008 to 2023; 15/05 from 2018. AP's 25/07 has no entry in any year (see below).\n  - MA: Corpus Christi from 2024; 08/03 from 2027. PB: 05/08 from 1968.\n  - SE: 08/07 from 1990; 24/10 from 1989 to 1999. PR: 19/12 from 1963 to 2013 (Lei PR 4.658/1962, revoked by Lei PR 18.384/2014).\n  - PE: 06/03 in 2008 and 2009 as `optional` (Lei PE 13.386/2007). AM: 08/12 as `optional` from 1999 (the state declares it a ponto facultativo in its offices by decree, DOE-AM of 02/12/2025; the earliest norm located is Lei Municipal de Manaus nº 496/1999). 2.4.0 listed it from 1900.\n- Returns an empty list when the argument is neither a number nor an object.\n- Municipal holidays are not covered.\n- One-year moves made by decree are not applied; the table keeps the statutory date. Examples: Decreto GO nº 10.935/2026 moved 26/07/2026 to 20/07, and Goiás moved 28/10/2026 to 30/10.\n- Also not applied: Acre's law that moves the holidays falling Tuesday to Thursday to the Friday (Lei AC nº 2.126/2009), because the state's own yearly decrees apply it unevenly (2026 moves 20/01 and leaves 17/11, a Tuesday, in place).",
      "params": [
        {
          "name": "options",
          "type": "GetHolidaysParams"
        }
      ],
      "returns": "Holiday[]",
      "cases": [
        {
          "id": "date.getHolidays#unknown-state",
          "args": [
            {
              "year": 2024,
              "stateCode": "XX"
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "from the maintainer briefing, #603: changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#empty-state",
          "args": [
            {
              "year": 2024,
              "stateCode": ""
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#blank-state",
          "args": [
            {
              "year": 2024,
              "stateCode": "   "
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#spaced-letters",
          "args": [
            {
              "year": 2024,
              "stateCode": "S P"
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#prototype-key",
          "args": [
            {
              "year": 2024,
              "stateCode": "__proto__"
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#numeric-state",
          "args": [
            {
              "year": 2024,
              "stateCode": 5
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#null-state",
          "args": [
            {
              "year": 2024,
              "stateCode": null
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#object-state",
          "args": [
            {
              "year": 2024,
              "stateCode": {}
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "changed in 2.5.0 (#603): a stateCode that is not a state code is rejected; 2.4.0 returned the national holidays"
        },
        {
          "id": "date.getHolidays#year-before-1900",
          "args": [
            {
              "year": 1899
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "JavaScript's own test: should return an empty array for a year outside 1900-2099"
        },
        {
          "id": "date.getHolidays#year-after-2099",
          "args": [
            {
              "year": 2100,
              "stateCode": "SP"
            }
          ],
          "expect": {
            "returns": []
          },
          "note": "JavaScript's own test: should return an empty array for a year outside 1900-2099"
        },
        {
          "id": "date.getHolidays#fractional-year",
          "args": [
            {
              "year": 2024.5
            }
          ],
          "expect": {
            "returns": []
          }
        },
        {
          "id": "date.getHolidays#string-year",
          "args": [
            {
              "year": "2024"
            }
          ],
          "expect": {
            "returns": []
          }
        },
        {
          "id": "date.getHolidays#missing-year",
          "args": [
            {}
          ],
          "expect": {
            "returns": []
          }
        },
        {
          "id": "date.getHolidays#null-options",
          "args": [
            null
          ],
          "expect": {
            "returns": []
          }
        }
      ]
    },
    {
      "id": "date.isBusinessDay",
      "level": "extended",
      "summary": "Checks whether a date is a Brazilian business day (dia útil).",
      "description": "Checks whether a date is a Brazilian business day (dia útil), by its local calendar date. A business day is not a Saturday, a Sunday or a holiday of `date.getHolidays` for the same state.\n\n- `options.includeOptional` (default true) counts the optional holidays (Carnaval Monday and Tuesday, Corpus Christi, and the `optional` entries a state has, AM's 8 December and PE's 6 March of 2008 and 2009) as non-business days. With false, only `national` and `state` holidays count, so Corpus Christi still counts in DF, in MA from 2024 and in RJ from 2026, where it is a state holiday.\n- `options.includeSaturday` (default false) counts Saturday as a business day, the labor law count of the payroll deadline (CLT art. 459 § 1º, read through IN MTP nº 2/2021, art. 14, I). Sunday and holidays stay excluded, including a holiday on a Saturday (Finados 2024-11-02, Independência 2024-09-07).\n- `includeSaturday` does not cover municipal holidays, which the IN also excludes. An exact count for a municipality has to remove them separately. The option name does not promise \"CLT\" for that reason.\n- A truthy value that is not a boolean (for example `\"false\"`) turns `includeSaturday` or `includeOptional` on.\n- An `options` that is not an object is ignored, as if it were omitted.\n- `options.stateCode` is read ignoring case and surrounding whitespace, as in every state util: `\"sp\"` and `\" SP \"` add the holidays of São Paulo. Only an omitted (`undefined`) `stateCode` means national holidays only.\n- A `stateCode` that is present and is not a state code (`\"XX\"`, `\"\"`, `\"__proto__\"`, a number, `null`, an object) is rejected: the function returns `false` without looking at the date. 2.4.0 silently fell back to the national holidays for an unknown or lowercase code, so `\"sp\"` counted 9 July as a business day in São Paulo.\n- This is not by itself a bank or court calendar: banks also close on their branch's local holidays, and courts follow their own calendars.\n- Returns false for an invalid date or a year outside 1900 to 2099.",
      "params": [
        {
          "name": "value",
          "type": "date"
        },
        {
          "name": "options",
          "type": "BusinessDayOptions",
          "optional": true
        }
      ],
      "returns": "boolean",
      "cases": []
    },
    {
      "id": "date.isHoliday",
      "level": "core",
      "summary": "Checks whether a date is a Brazilian holiday.",
      "description": "Checks whether a date is a Brazilian holiday, by its local calendar date.\n\n- `options` carries the target date and, optionally, a state code whose holidays also count. Every holiday `date.getHolidays` lists counts, optional ones and the first round of the elections included.\n- `options.stateCode` is read ignoring case and surrounding whitespace, as in every state util: `\"sp\"` and `\" SP \"` add the holidays of São Paulo. Only an omitted (`undefined`) `stateCode` means national holidays only.\n- A `stateCode` that is present and is not a state code (`\"XX\"`, `\"\"`, `\"__proto__\"`, a number, `null`, an object) is rejected: the function returns `false` without looking at the date. 2.4.0 silently fell back to the national holidays for an unknown or lowercase code, so `\"sp\"` did not find 9 July as a holiday in São Paulo.\n- `options.targetDate` is the date to check. It is read by its local calendar day, not by its UTC instant. `options.stateCode` is optional.\n- Returns false when `targetDate` is missing or is not a valid date, and when `stateCode` is present and is not a state code, even on a national holiday.\n- Returns false for a year outside 1900 to 2099, where `date.getHolidays` lists nothing.\n- The `optional` and `religious` entries of `date.getHolidays` count: Carnaval Monday and Tuesday, Corpus Christi and Páscoa make the function return `true`. There is no `includeOptional` here, unlike `date.isBusinessDay`.",
      "params": [
        {
          "name": "options",
          "type": "IsHolidayParams",
          "optional": true
        }
      ],
      "returns": "boolean",
      "cases": [
        {
          "id": "date.isHoliday#[]",
          "args": [],
          "expect": {
            "returns": false
          },
          "note": "JavaScript's own test: should return false when called without arguments"
        },
        {
          "id": "date.isHoliday#unknown-state-without-date",
          "args": [
            {
              "stateCode": "XX"
            }
          ],
          "expect": {
            "returns": false
          }
        },
        {
          "id": "date.isHoliday#date-as-string",
          "args": [
            {
              "targetDate": "2024-01-01"
            }
          ],
          "expect": {
            "returns": false
          },
          "note": "JavaScript's own test: should return false when targetDate is a string instead of a Date"
        },
        {
          "id": "date.isHoliday#null-options",
          "args": [
            null
          ],
          "expect": {
            "returns": false
          },
          "note": "JavaScript's own test: should return false when called without arguments"
        },
        {
          "id": "date.isHoliday#unknown-state-with-string-date",
          "args": [
            {
              "targetDate": "2024-01-01",
              "stateCode": "XX"
            }
          ],
          "expect": {
            "returns": false
          },
          "note": "a stateCode that is not a state code is rejected, and so is a targetDate that is not a date"
        }
      ]
    },
    {
      "id": "date.subBusinessDays",
      "level": "extended",
      "summary": "Subtracts a number of Brazilian business days (dias úteis) from a date.",
      "description": "Subtracts a number of Brazilian business days from a date. This is the same as `date.addBusinessDays` with the opposite `amount`.\n\n- Same rules and options as `date.addBusinessDays` (`includeOptional`, `includeSaturday`, `stateCode`), including the same caveat on the time of day. A negative `amount` walks forwards.\n- Last business day of a month: `subBusinessDays(new Date(y, m + 1, 1), 1)`. For December 2099 this returns `null`, because the starting day is in 2100.",
      "params": [
        {
          "name": "date",
          "type": "date"
        },
        {
          "name": "amount",
          "type": "number"
        },
        {
          "name": "options",
          "type": "BusinessDayOptions",
          "optional": true
        }
      ],
      "returns": "date?",
      "cases": []
    }
  ]
}
