工作周计算BUG修复

This commit is contained in:
黎润豪 2026-04-15 17:21:12 +08:00
parent 1aadf8cd2e
commit 14b2bc40ad
1 changed files with 48 additions and 34 deletions

View File

@ -87,15 +87,53 @@ function getWeekEndDate(weekStartDate) {
/**
* 获取 ISO 周编号 (YYYY-Www)
* 遵循 ISO 8601 标准每周从周一开始第一个包含1月4日的周是W1
*/
function getWeekNumber(dateStr) {
const date = new Date(dateStr);
// ISO 周码每年的第一个周四所在的周为第1周
const MS_PER_DAY = 24 * 60 * 60 * 1000;
// 找到该日期所在周的周四ISO 8601 以包含1月4日的周为W1
const thursday = new Date(date);
thursday.setDate(date.getDate() + (4 - (date.getDay() === 0 ? 7 : date.getDay())));
// 计算该年的1月1日是周几
const yearStart = new Date(thursday.getFullYear(), 0, 1);
const weekNum = Math.ceil(((thursday - yearStart) / 86400000 + 1) / 7);
return `${thursday.getFullYear()}-W${String(weekNum).padStart(2, '0')}`;
const jan1Day = yearStart.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat
// 计算这是该年的第几天1月1日=1
const dayOfYear = Math.floor((thursday - yearStart) / MS_PER_DAY) + 1;
// ISO 周号:(dayOfYear + 该年1月1日的星期几 - 1) / 7 向上取整
// 如果1月1日是周四(day=4),则 Jan1 就在 W01 中
// 如果1月1日是周五/周六/周日,则需要调整(这些天属于上一年最后一周)
const weekNum = Math.ceil((dayOfYear + (jan1Day === 0 ? 6 : jan1Day) - 1) / 7);
// 处理年末/年初边界情况:
// 如果计算的周号是0说明属于上一年最后一周
// 如果周号超过该年最大周数,说明属于下一年第一周
let year = thursday.getFullYear();
let finalWeek = weekNum;
if (finalWeek === 0) {
// 上一年最后一周
year = year - 1;
const prevJan1Day = new Date(year, 0, 1).getDay();
finalWeek = prevJan1Day === 4 || (prevJan1Day === 3 && isLeapYear(year)) ? 53 : 52;
} else {
const maxWeeks = (jan1Day === 4 || (jan1Day === 3 && isLeapYear(thursday.getFullYear()))) ? 53 : 52;
if (finalWeek > maxWeeks) {
// 下一年第一周
year = year + 1;
finalWeek = 1;
}
}
return `${year}-W${String(finalWeek).padStart(2, '0')}`;
}
function isLeapYear(year) {
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}
/**
@ -188,37 +226,13 @@ function getWeekStartFromWeekNumber(year, weekNum) {
const jan4 = new Date(year, 0, 4);
const jan4Day = jan4.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat
// 找到W1的周一
let firstMonday;
if (jan4Day === 1) {
// 1月4日是周一 -> W1周一是1月4日
firstMonday = jan4;
} else if (jan4Day === 0) {
// 1月4日是周日 -> W1周一是上周一12月X日
// 1月4日 - 7天 = 12月28日上上个周一再 -1天 = 12月29日上周一
firstMonday = new Date(jan4.getTime() - 7 * MS_PER_DAY);
// 但这已经是12月28了而1月4日是周日那上周一是12月29日
// 所以实际上 1月4日 - 8天 = 12月27... 这不对
// 让我重新想:
// 如果1月4日是周日那这一周是 Dec 28 - Jan 3 (W1 ends Jan 3)
// 所以W1的周一是 Dec 28
// 那么 Dec 28 + 7 = Jan 4W2从 Jan 5开始
// 所以 W1 of 2026 = Dec 28 - Jan 3
// W1 starts on Monday Dec 28
// Let me recalculate: Jan 4 - 6 = Dec 29 (that's Monday if Jan 4 is Sunday)
// Wait, if Jan 4 is Sunday, then Jan 4 - 1 = Jan 3 (Saturday)
// Jan 4 - 2 = Jan 2, ..., Jan 4 - 7 = Dec 28
// But that's 7 days back, not 6. And Dec 28 is Monday?
// Let me just use getTime()
const daysToSubtract = jan4Day === 0 ? 6 : jan4Day - 1;
firstMonday = new Date(jan4.getTime() - daysToSubtract * MS_PER_DAY);
} else {
// 1月4日是 Tue(2), Wed(3), Thu(4), Fri(5), Sat(6) -> 找到上溯到周一
// 如果1月4日是周三那周一就是1月4日 - 2天
// daysToSubtract = 4 - 1 = 3, 1月4日 - 3天 = 1月1日 = 周一 ✓
const daysToSubtract = jan4Day - 1;
firstMonday = new Date(jan4.getTime() - daysToSubtract * MS_PER_DAY);
}
// 找到W1的周一ISO 8601每年第一个包含1月4日的周是W1该周的周一是W1起始
// jan4Day: 0=Sun, 1=Mon, ..., 6=Sat
// 如果1月4日是周日W1周一是Dec 29上周一
// 如果1月4日是周一W1周一是1月4日
// 否则W1周一是1月4日往前到周一的天数
const daysToSubtract = (jan4Day === 0 ? 7 : jan4Day) - 1;
const firstMonday = new Date(jan4.getTime() - daysToSubtract * MS_PER_DAY);
// 计算目标周的周一
const targetMonday = new Date(firstMonday.getTime() + (weekNum - 1) * 7 * MS_PER_DAY);