@@ -34,7 +34,7 @@ const CURRENT_MILLENIUM = 2000;
3434 *
3535 * @param currentDate Current date
3636 */
37- export function getAcademicYear ( currentDate : Date ) {
37+ export function getAcademicYear ( currentDate : Date ) : AcademicYear {
3838 // Extract the year
3939 const year = currentDate . getFullYear ( ) ;
4040 const currentYearShort = year - CURRENT_MILLENIUM ;
@@ -45,3 +45,77 @@ export function getAcademicYear(currentDate: Date) {
4545 // Otherwise, we are in the previous academic year
4646 return `${ currentYearShort - 1 } -${ currentYearShort } ` ;
4747}
48+
49+ /**
50+ * Generates a list of academic years between a start date and an end date.
51+ *
52+ * An academic year runs from 1st August of one year to 31st July of the next year.
53+ * The function returns academic years in the format `shortyear-shortyear` (e.g., '20-21', '23-24') - see {@link AcademicYear}.
54+ *
55+ * **Allowed Date Range:**
56+ * - Earliest allowed start date: 1st August 2020
57+ * - Latest allowed end date: 31st July 2099
58+ *
59+ * @param endDate - The end date up to which academic years should be generated. Must be within the allowed range.
60+ * @param startDate - The start date from which to begin generating academic years. Defaults to 1st August 2020 (so academic year '20-21').
61+ * @returns An array of academic years between the start and end dates, inclusive.
62+ *
63+ * @throws Will throw an error if the provided dates are outside the allowed range.
64+ * @throws Will return an empty array if the start date is after the end date.
65+ *
66+ * @example
67+ * ```typescript
68+ * getAcademicYears(new Date("2024-08-01"), new Date("2022-07-31"));
69+ * // Returns: ['21-22', '22-23', '23-24', '24-25']
70+ *
71+ * getAcademicYears(new Date("2024-06-30"), new Date("2023-09-01"));
72+ * // Returns: ['23-24']
73+ * ```
74+ */
75+ export function getAcademicYears (
76+ endDate : Date ,
77+ startDate : Date = new Date ( "2020-08-01" ) ,
78+ ) : AcademicYear [ ] {
79+ const earliestDate = new Date ( "2010-08-01" ) ;
80+ const latestDate = new Date ( "2099-07-31" ) ;
81+
82+ // Ensure dates are within the allowed range
83+ if ( startDate < earliestDate || endDate > latestDate ) {
84+ throw new Error (
85+ "Dates must be within the range from 1st August 2020 to 31st July 2099, and the start date must be before the end date." ,
86+ ) ;
87+ }
88+
89+ if ( startDate > endDate ) {
90+ return [ ] ;
91+ }
92+
93+ const academicYears : AcademicYear [ ] = [ ] ;
94+
95+ let startYear = startDate . getFullYear ( ) ;
96+ const startMonth = startDate . getMonth ( ) ;
97+
98+ // Adjust startYear if the startDate is before 1st August of the same year
99+ if ( startMonth < 7 ) {
100+ // Month is zero-indexed, so July is 6
101+ startYear -- ;
102+ }
103+
104+ let endYear = endDate . getFullYear ( ) ;
105+ const endMonth = endDate . getMonth ( ) ;
106+
107+ // Adjust endYear if the endDate is before 1st August of the same year
108+ if ( endMonth < 7 ) {
109+ // Month is zero-indexed, so July is 6
110+ endYear -- ;
111+ }
112+
113+ // Generate academic years
114+ for ( let year = startYear ; year <= endYear ; year ++ ) {
115+ const nextYear = year + 1 ;
116+ const academicYear : AcademicYear = `${ year % 100 } -${ nextYear % 100 } ` as AcademicYear ;
117+ academicYears . push ( academicYear ) ;
118+ }
119+
120+ return academicYears ;
121+ }
0 commit comments