diff --git a/src/public/app/widgets/buttons/calendar.ts b/src/public/app/widgets/buttons/calendar.ts index 87803f6cb..8c0c89f77 100644 --- a/src/public/app/widgets/buttons/calendar.ts +++ b/src/public/app/widgets/buttons/calendar.ts @@ -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;