fix: 🐛 fix week number cross years

This commit is contained in:
Jin 2025-04-01 00:04:09 +02:00
parent be0b66c104
commit d7e809b059

View File

@ -10,10 +10,11 @@ import { Dropdown } from "bootstrap";
import type { EventData } from "../../components/app_context.js"; import type { EventData } from "../../components/app_context.js";
import dayjs, { Dayjs } from "dayjs"; import dayjs, { Dayjs } from "dayjs";
import utc from "dayjs/plugin/utc.js"; import utc from "dayjs/plugin/utc.js";
import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js";
import "../../../stylesheets/calendar.css"; import "../../../stylesheets/calendar.css";
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(isSameOrAfter);
const MONTHS = [ const MONTHS = [
t("calendar.january"), t("calendar.january"),
t("calendar.febuary"), t("calendar.febuary"),
@ -205,59 +206,67 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
getWeekNumber(date: Dayjs): number { getWeekNumber(date: Dayjs): number {
const year = date.year(); const year = date.year();
const jan1 = date.clone().startOf('year'); const dayOfWeek = (day: number) => (day - this.firstDayOfWeek + 7) % 7;
const jan1Day = jan1.day();
let firstWeekStart = jan1.clone(); // Get first day of the year and adjust to first week start
const jan1 = date.clone().year(year).month(0).date(1);
let dayOffset; const jan1Weekday = jan1.day();
if (jan1Day < this.firstDayOfWeek) { const dayOffset = dayOfWeek(jan1Weekday);
dayOffset = jan1Day + (7 - this.firstDayOfWeek); let firstWeekStart = jan1.clone().subtract(dayOffset, 'day');
} else {
dayOffset = jan1Day - this.firstDayOfWeek;
}
firstWeekStart = firstWeekStart.subtract(dayOffset, 'day');
// Adjust based on week rule
switch (this.weekCalculationOptions.firstWeekType) { switch (this.weekCalculationOptions.firstWeekType) {
// case 0 is default: week containing Jan 1 case 1: { // ISO 8601: first week contains Thursday
case 1: { const thursday = firstWeekStart.clone().add(3, 'day'); // Monday + 3 = Thursday
let thursday = firstWeekStart.clone();
const day = thursday.day();
const offset = (4 - day + 7) % 7;
thursday = thursday.add(offset, 'day');
if (thursday.year() < year) { if (thursday.year() < year) {
firstWeekStart = firstWeekStart.add(7, 'day'); firstWeekStart = firstWeekStart.add(7, 'day');
} }
break; break;
} }
case 2: { case 2: { // minDaysInFirstWeek rule
const daysInFirstWeek = 7 - dayOffset; const daysInFirstWeek = 7 - dayOffset;
if (daysInFirstWeek < this.weekCalculationOptions.minDaysInFirstWeek) { if (daysInFirstWeek < this.weekCalculationOptions.minDaysInFirstWeek) {
firstWeekStart = firstWeekStart.add(7, 'day'); firstWeekStart = firstWeekStart.add(7, 'day');
} }
break; break;
} }
// default case 0: week containing Jan 1 → already handled
} }
const diffDays = date.diff(firstWeekStart, 'day') + 1; const diffDays = date.startOf('day').diff(firstWeekStart.startOf('day'), 'day');
const weekNumber = Math.floor(diffDays / 7) + 1; const weekNumber = Math.floor(diffDays / 7) + 1;
// Check if the week number is less than 0, which means the date is in the previous year // Handle case when date is before first week start → belongs to last week of previous year
if (weekNumber <= 0) { if (weekNumber <= 0) {
const prevYearLastWeek = this.getWeekNumber(date.subtract(1, 'year').endOf('year')); return this.getWeekNumber(date.subtract(1, 'day'));
return prevYearLastWeek;
} }
// Check if it's the last week of December // Handle case when date belongs to first week of next year
if (date.month() === 11) { // December const nextYear = year + 1;
const lastDayOfYear = date.clone().month(11).date(31); const jan1Next = date.clone().year(nextYear).month(0).date(1);
const lastWeekStart = lastDayOfYear.subtract((lastDayOfYear.day() - this.firstDayOfWeek + 7) % 7, 'day'); const jan1WeekdayNext = jan1Next.day();
const offsetNext = dayOfWeek(jan1WeekdayNext);
let nextYearWeekStart = jan1Next.clone().subtract(offsetNext, 'day');
// Use local timezone to avoid date mismatch switch (this.weekCalculationOptions.firstWeekType) {
if (date.isSame(lastWeekStart, 'day')) { case 1: {
const nextYearFirstWeek = this.getWeekNumber(lastDayOfYear.add(1, 'day')); const thursday = nextYearWeekStart.clone().add(3, 'day');
return nextYearFirstWeek; if (thursday.year() < nextYear) {
nextYearWeekStart = nextYearWeekStart.add(7, 'day');
}
break;
} }
case 2: {
const daysInFirstWeek = 7 - offsetNext;
if (daysInFirstWeek < this.weekCalculationOptions.minDaysInFirstWeek) {
nextYearWeekStart = nextYearWeekStart.add(7, 'day');
}
break;
}
}
if (date.isSameOrAfter(nextYearWeekStart)) {
return 1;
} }
return weekNumber; return weekNumber;