40 lines
1.5 KiB
JavaScript
40 lines
1.5 KiB
JavaScript
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
||
|
||
export function academicCalendarWeekNumber(academicYearStartIso, dateIso) {
|
||
const academicYearStart = parseIsoDate(academicYearStartIso);
|
||
const date = parseIsoDate(dateIso);
|
||
const daysFromYearStart = (date.timestamp - academicYearStart.timestamp) / MILLISECONDS_PER_DAY;
|
||
|
||
if (!Number.isInteger(daysFromYearStart) || daysFromYearStart < 0) {
|
||
throw new RangeError('Дата ячейки не может быть раньше начала учебного года');
|
||
}
|
||
|
||
const daysBeforeYearStartInFirstWeek = academicYearStart.dayOfWeek - 1;
|
||
return Math.floor((daysBeforeYearStartInFirstWeek + daysFromYearStart) / 7) + 1;
|
||
}
|
||
|
||
function parseIsoDate(value) {
|
||
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(value));
|
||
if (!match) {
|
||
throw new TypeError('Ожидалась дата в формате ГГГГ-ММ-ДД');
|
||
}
|
||
|
||
const [, yearText, monthText, dayText] = match;
|
||
const year = Number(yearText);
|
||
const month = Number(monthText);
|
||
const day = Number(dayText);
|
||
const timestamp = Date.UTC(year, month - 1, day);
|
||
const date = new Date(timestamp);
|
||
if (date.getUTCFullYear() !== year
|
||
|| date.getUTCMonth() !== month - 1
|
||
|| date.getUTCDate() !== day) {
|
||
throw new TypeError('Ожидалась дата в формате ГГГГ-ММ-ДД');
|
||
}
|
||
|
||
const jsDayOfWeek = date.getUTCDay();
|
||
return {
|
||
timestamp,
|
||
dayOfWeek: jsDayOfWeek === 0 ? 7 : jsDayOfWeek
|
||
};
|
||
}
|