应使用date_sub(now(), interval weekday(now()) day)获取本周一,因weekday()返回0-6且不受跨年周和week() mode影响,而str_to_date+date_format组合不可靠。

MySQL中用STR_TO_DATE和DATE_FORMAT算本周一是错的路
直接组合这两个函数无法可靠获取本周一——因为STR_TO_DATE需要明确的字符串输入,而“本周一”是动态偏移量,不是固定格式文本。强行拼接比如STR_TO_DATE(CONCAT(YEARWEEK(NOW()), '1'), '%X%V%w')看似能用,但会受default_week_format系统变量影响,在跨年周(如2024-12-30属2025年第1周)时返回错误日期,且不兼容WEEK()不同mode参数的语义。
真正可靠的方案:用DATE_SUB + WEEKDAY
WEEKDAY()返回0(周一)到6(周日),比DAYOFWEEK()更符合日常习惯;配合DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY)就能稳稳拿到本周一的0点时间。注意它默认返回datetime类型,如果只要日期部分,再套一层DATE()即可。
常见写法:
SELECT DATE(DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY)) AS monday_this_week;
使用场景包括:统计本周数据、生成周报起始时间、作为分区键计算依据。若业务要求周日为每周第一天,改用DAYOFWEEK(NOW()) - 1(注意DAYOFWEEK()周日=1,所以减1后周日=0),但需额外处理结果为0的情况(即当天是周日)。
为什么不用DATE_ADD + FROM_DAYS这类偏门技巧
有人用FROM_DAYS(TO_DAYS(NOW()) - WEEKDAY(NOW())),逻辑上可行,但TO_DAYS()在远古日期(如公元前)或超大日期下有溢出风险;FROM_DAYS也不支持毫秒级精度。而DATE_SUB走的是原生日期运算路径,MySQL优化器能更好识别,执行计划更稳定。另外,所有方案都默认按服务器时区计算,如果应用跨时区,务必确认time_zone设置,否则凌晨任务可能错位一天。
容易被忽略的边界:跨年周与WEEK() mode差异
当1月1日是周五/周六/周日时,“本周一”可能落在上一年末。比如2025-01-01是周三,那2025年第1周的周一其实是2024-12-30。此时WEEK(NOW(), 1)和WEEK(NOW(), 0)返回的周数不同,但WEEKDAY()不受影响——它只看当前日期本身是星期几,不依赖“第几周”的定义。所以只要目标是“离今天最近的、往前推的周一”,就别碰WEEK()相关函数,纯用WEEKDAY()最干净。











