diff --git a/Maths/IsLeapYear.ts b/Maths/IsLeapYear.ts new file mode 100644 index 00000000..0d607bb5 --- /dev/null +++ b/Maths/IsLeapYear.ts @@ -0,0 +1,18 @@ +/** + * @function IsLeapYear + * @description Checks if a year is a leap year (Gregorian calendar). + * A year is a leap year if it is divisible by 4 but not by 400 or if it is divisible by 400. + * @param {number} year - A year, natural number > 0. + * @return {boolean} - True if given year is a leap year. + * @see https://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar + * @example IsLeapYear(2000) = true + * @example IsLeapYear(2001) = false + */ + +export const IsLeapYear = (year: number): boolean => { + if (year <= 0 || !Number.isInteger(year)) { + throw new Error("year must be a natural number > 0"); + } + + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); +}; diff --git a/Maths/test/IsLeapYear.test.ts b/Maths/test/IsLeapYear.test.ts new file mode 100644 index 00000000..79acb8bd --- /dev/null +++ b/Maths/test/IsLeapYear.test.ts @@ -0,0 +1,66 @@ +import { IsLeapYear } from "../IsLeapYear"; + +describe("IsLeapYear", () => { + test.each([4, 8, 12, 2004])( + "a year is a leap year it is divisible by 4 but not by 400 like %i", + (year) => { + expect(year % 4 === 0).toBe(true); + expect(year % 400 === 0).toBe(false); + expect(IsLeapYear(year)).toBe(true); + }, + ); + + test.each([400, 800, 1200, 1600, 2000, 2400, 40000])( + "a year is a leap year it is divisible by 400 like %i", + (year) => { + expect(year % 400 === 0).toBe(true); + expect(IsLeapYear(year)).toBe(true); + }, + ); + + test.each([1, 313, 1997, 2001, 2021, 13337])( + "a year is not a leap year if it is not divisible by 4 like %i", + (year) => { + expect(year % 4 === 0).toBe(false); + expect(IsLeapYear(year)).toBe(false); + }, + ); + + test.each([100, 200, 300, 700, 2100])( + "a year is not a leap year if it is divisible by 100 but not by 400 like %i", + (year) => { + expect(year % 100 === 0).toBe(true); + expect(year % 400 === 0).toBe(false); + expect(IsLeapYear(year)).toBe(false); + }, + ); + + test.each([1, 2022, 3000000])( + "a year is supported if it is a natural number > 0 like %i", + (year) => { + expect(year > 0).toBe(true); + expect(Number.isInteger(year)).toBe(true); + expect(() => IsLeapYear(year)).not.toThrow(); + }, + ); + + test.each([-1, -10, -Infinity])( + "a year is not supported if it is negative like %i", + (year) => { + expect(year < 0).toBe(true); + expect(() => IsLeapYear(year)).toThrow("year must be a natural number > 0"); + }, + ); + + test.each([0.1, 1.2, 4.2])( + "a year is not supported if it is not an integer %d", + (year) => { + expect(Number.isInteger(year)).toBe(false); + expect(() => IsLeapYear(year)).toThrow("year must be a natural number > 0"); + }, + ); + + test("a year is not supported if it is 0", () => { + expect(() => IsLeapYear(0)).toThrow("year must be a natural number > 0"); + }) +});