weekday()返回0(周一)至6(周日),dayofweek()返回1(周日)至7(周六);计算本周第一天需据业务选函数:周一始用weekday(),周日始用dayofweek();where中应避免函数作用于字段,改用日期范围条件以利用索引。

MySQL中WEEKDAY()和DAYOFWEEK()的区别直接影响结果
MySQL里算“本周第一天”,关键看业务定义:是周一为周始(ISO标准),还是周日为周始?WEEKDAY()返回0=周一,6=周日;DAYOFWEEK()返回1=周日,7=周六。用错函数会导致日期偏移一天。
常见错误现象:SELECT DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY) 得到的是**上周日**,不是本周日——因为DAYOFWEEK('2024-06-10')(周一)是2,减1后回退1天,得到上周一而非本周一。
- 若要“周一为本周第一天”,用
WEEKDAY():周一=0,所以DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) - 若要“周日为本周第一天”,用
DAYOFWEEK():周日=1,所以DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY) - 注意:
WEEKDAY()在所有MySQL版本中行为一致;DAYOFWEEK()在某些旧版本(如5.5)对NULL处理更敏感
获取本周最后一天的三种可靠写法
“最后一天”本质是“第一天 + 6 天”,但直接加容易忽略时区或夏令时影响(虽MySQL日期计算不涉及时分秒,仍建议统一用日期函数链式计算)。
推荐用 DATE_ADD() 基于第一天推导,避免用 LAST_DAY()(那是取当月最后一天,完全无关)或 ADDDATE()(别名虽可用,但可读性差)。
- 周一为周始:
DATE_ADD(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY), INTERVAL 6 DAY) - 周日为周始:
DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 6 DAY) - 更简洁写法(等价):
DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE())-6 DAY)—— 本质是“往前推0天,再往后推6天”,但逻辑不如分两步清晰
WHERE子句中高效过滤本周数据的写法
直接在 WHERE 中用函数包裹字段(如 WHERE WEEKDAY(create_time) = WEEKDAY(CURDATE()))会导致全表扫描——create_time 上的索引无法生效。
必须把范围转换成两个确定日期边界,让优化器能走索引:
- 周一为周始:
WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) AND create_time - 注意用
而非 <code>,避免跨到下周零点;时间类型字段(<code>DATETIME)默认包含时分秒,边界必须严格 - 如果字段是
DATE类型且无时分秒,也可,但统一用 <code> 更安全
跨年/跨月时CURDATE()是否可靠?
可靠。CURDATE() 返回当前日期(不含时间部分),不受时区会话变量(time_zone)影响——它基于系统日期,不是基于会话时间戳。即使服务器时区设为 '+00:00',CURDATE() 仍是本地系统日期。
真正要注意的是:如果业务部署在多个时区,且需按用户所在时区算“本周”,就不能只靠 CURDATE();得先用 CONVERT_TZ(NOW(), '+00:00', @user_tz) 转换时间,再取日期。但这时已不是纯日期计算问题,而是时区上下文问题。
多数内部系统按服务器本地时间算本周即可,CURDATE() 完全够用。别为了“看起来通用”强行加时区转换,反而引入NULL风险和性能开销。











