原理是weekday()返回0(周一)至6(周日),即日期距本周一的天数,date_sub(date, interval weekday(date) day)据此回退至当周周一;例如'2024-06-12'(周三)减2天得'2024-06-10'(周一)。

DATE_SUB + WEEKDAY 计算当周周一的原理
MySQL 中 WEEKDAY() 返回 0 表示周一、1 表示周二……6 表示周日。所以对任意日期 date,WEEKDAY(date) 就是它距离本周一的天数。用 DATE_SUB(date, INTERVAL WEEKDAY(date) DAY) 就能回退到当周周一。
直接可用的 SQL 表达式
假设输入日期是 '2024-06-12'(周三),执行:
SELECT DATE_SUB('2024-06-12', INTERVAL WEEKDAY('2024-06-12') DAY);
结果是 '2024-06-10'(周一)。这个表达式可直接用于 SELECT、WHERE 或计算字段。常见用法包括:
- 作为查询字段:
DATE_SUB(created_at, INTERVAL WEEKDAY(created_at) DAY) AS week_start - 按周分组:
GROUP BY DATE_SUB(created_at, INTERVAL WEEKDAY(created_at) DAY) - 筛选本周数据:
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY)
注意 WEEKDAY 和 DAYOFWEEK 的区别
容易混淆的是 DAYOFWEEK():它返回 1=周日、2=周一……7=周六,和 WEEKDAY() 起始点不同。如果误用 DAYOFWEEK(),会多减 1 天或少减 1 天——比如 DAYOFWEEK('2024-06-12') 是 4,DATE_SUB(... INTERVAL 4 DAY) 得到的是上周六,不是周一。
务必确认函数名,尤其从其他数据库(如 PostgreSQL)迁移过来时,习惯可能不同。
跨月或跨年时的表现是否可靠
完全可靠。DATE_SUB 和 WEEKDAY 都是纯日期运算,不依赖月份长度或年份规则。例如 '2024-01-01'(周一)本身 WEEKDAY() 是 0,DATE_SUB 不做任何偏移;而 '2023-12-31'(周日)的 WEEKDAY() 是 6,减 6 天得到 '2023-12-25'(前一周一),逻辑清晰无歧义。
唯一要注意的是:如果你的业务定义“周”以周日为起点(如美国习惯),那这个公式就不适用,得改用 DATE_SUB(date, INTERVAL (DAYOFWEEK(date) - 1) DAY) 并确保理解 DAYOFWEEK 的偏移含义。











