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