Skip to content
Closed
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
1 change: 1 addition & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('Public API', () => {
'capitalize',
'formatCurrency',
'parseCurrency',
'getAllNationalHolidays',
];

Object.keys(API).forEach((method) => {
Expand Down
61 changes: 61 additions & 0 deletions src/utilities/holidays/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { getAllNationalHolidays } from '.';

describe('getAllNationalHolidays', () => {
test('should return fixed holidays for the given year', () => {
const year = 2024;
const holidays = getAllNationalHolidays(year);

const fixedHolidays = [
{ name: 'Ano novo', date: new Date(year, 0, 1) },
{ name: 'Tiradentes', date: new Date(year, 3, 21) },
{ name: 'Dia do trabalhador', date: new Date(year, 4, 1) },
{ name: 'Independência do Brasil', date: new Date(year, 8, 7) },
{ name: 'Nossa Senhora Aparecida', date: new Date(year, 9, 12) },
{ name: 'Finados', date: new Date(year, 10, 2) },
{ name: 'Proclamação da República', date: new Date(year, 10, 15) },
{ name: 'Dia da Consciência Negra', date: new Date(year, 10, 20) },
{ name: 'Natal', date: new Date(year, 11, 25) },
];

fixedHolidays.forEach(({ name, date }) => {
expect(holidays).toContainEqual({ name, date });
});
});

test('should calculate Easter-related holidays correctly', () => {
const year = 2024;
const holidays = getAllNationalHolidays(year);

const easterDate = new Date(2024, 2, 31); // Easter Sunday 2024
const expectedHolidays = [
{ name: 'Páscoa', date: easterDate },
{ name: 'Carnaval (terça-feira)', date: new Date(2024, 1, 13) },
{ name: 'Sexta-feira Santa', date: new Date(2024, 2, 29) },
{ name: 'Corpus Christi', date: new Date(2024, 5, 9) },
];

expectedHolidays.forEach(({ name, date }) => {
expect(holidays).toContainEqual({ name, date });
});
});

test('should return the correct number of holidays', () => {
const year = 2024;
const holidays = getAllNationalHolidays(year);

expect(holidays.length).toBe(13); // 9 fixed + 4 Easter-related holidays
});

test('should work for leap years', () => {
const year = 2020;
const holidays = getAllNationalHolidays(year);

expect(holidays).toContainEqual({
name: 'Ano novo',
date: new Date(year, 0, 1),
});

const easterDate = new Date(2020, 3, 12); // Easter Sunday 2020
expect(holidays).toContainEqual({ name: 'Páscoa', date: easterDate });
});
});
88 changes: 88 additions & 0 deletions src/utilities/holidays/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const FIXED_HOLIDAYS = {
'Ano novo': { day: 1, month: 1 },
Tiradentes: { day: 21, month: 4 },
'Dia do trabalhador': { day: 1, month: 5 },
'Independência do Brasil': { day: 7, month: 9 },
'Nossa Senhora Aparecida': { day: 12, month: 10 },
Finados: { day: 2, month: 11 },
'Proclamação da República': { day: 15, month: 11 },
'Dia da Consciência Negra': { day: 20, month: 11 },
Natal: { day: 25, month: 12 },
};

function calculateEaster(year: number): Date {
// Calculation based on the computus algorithm
const a = year % 19;
const b = Math.floor(year / 100);
const c = year % 100;
const d = Math.floor(b / 4);
const e = b % 4;
const f = Math.floor((b + 8) / 25);
const g = Math.floor((b - f + 1) / 3);
const h = (19 * a + b - d - g + 15) % 30;
const i = Math.floor(c / 4);
const k = c % 4;
const l = (32 + 2 * e + 2 * i - h - k) % 7;
const m = Math.floor((a + 11 * h + 22 * l) / 451);

const month = Math.floor((h + l - 7 * m + 114) / 31) - 1; // 0-based month
const day = ((h + l - 7 * m + 114) % 31) + 1;

return new Date(year, month, day);
}

function calculateHolidayFromEaster(year: number, offset: number): Date {
// Calculates the date of Easter
const easterDate = calculateEaster(year);

// Creates a new Date object for the holiday
const holidayDate = new Date(easterDate);

// Adds or subtracts the offset to get the holiday date
holidayDate.setDate(easterDate.getDate() + offset);

return holidayDate;
}

export function getAllNationalHolidays(year: number): Object[] {
const allHolidays: Object[] = [];

// Add fixed holidays
for (const [key, { day, month }] of Object.entries(FIXED_HOLIDAYS)) {
const holiday = {
name: key,
date: new Date(year, month - 1, day),
};
allHolidays.push(holiday);
}

// Calculate and add Easter
const easterHoliday = {
name: 'Páscoa',
date: calculateEaster(year),
};
allHolidays.push(easterHoliday);

// Calculate Gras
const mardiGrasHoliday = {
name: 'Carnaval (terça-feira)',
date: calculateHolidayFromEaster(year, -47),
};
allHolidays.push(mardiGrasHoliday);

// Calculate Good Friday
const goodFridayHoliday = {
name: 'Sexta-feira Santa',
date: calculateHolidayFromEaster(year, -2),
};
allHolidays.push(goodFridayHoliday);

// Calculate and add Corpus Christi
const corpusChristiHoliday = {
name: 'Corpus Christi',
date: calculateHolidayFromEaster(year, 70),
};
allHolidays.push(corpusChristiHoliday);

return allHolidays;
}
1 change: 1 addition & 0 deletions src/utilities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export { format as formatCNPJ, generate as generateCNPJ, isValid as isValidCNPJ
export { capitalize } from './capitalize';
export { getStates } from './states';
export { getCities } from './cities';
export { getAllNationalHolidays } from './holidays';