PostgreSQL的DATE_TRUNC('week',...)默认以周日为起点且第1周含1月1日,不满足ISO 8601(周一为始、第1周含首个周四)时需用EXTRACT(isodow)或TO_DATE+IYYY-IW手动计算;SQL Server依赖DATEFIRST设置,须结合DATEADD与DATEPART反推;MySQL不支持week级DATE_TRUNC,需用WEEKDAY或YEARWEEK构造;跨库无统一方案,应明确业务语义并在应用层生成周日期后传入SQL。

DATE_TRUNC 在 PostgreSQL 中取周起始日要小心默认周定义
PostgreSQL 的 DATE_TRUNC('week', ...) 默认以周日为一周起点,且把“第1周”定义为包含1月1日的那周(ISO标准不适用)。如果业务要求周一为起点、或严格按 ISO 8601 周计算(即周一为每周第一天,第1周是包含当年第一个周四的那周),直接用 DATE_TRUNC('week', ...) 会出错。
实操建议:
- 要 ISO 周起始(周一),改用
TO_DATE(EXTRACT(year FROM d)::TEXT || '-' || EXTRACT(week FROM d)::TEXT, 'IYYY-IW')配合EXTRACT(isodow FROM d)调整偏移 - 若只要简单“本周周一”,用
d - EXTRACT(isodow FROM d)::INTEGER + 1(isodow周一=1,周日=7) -
DATE_TRUNC('week', d)返回的是周日 00:00,不是周一;别直接拿来算“第N周”的起始日
SQL Server 的 DATEPART 配合 DATEADD 才能反推周初
DATEPART(week, ...) 只返回数字,无法单独定位日期;必须结合 DATEADD 和基准日推算。而且 SQL Server 的周行为受 DATEFIRST 设置影响:默认 DATEFIRST 7(周日为第一天),但 DATEPART(week, ...) 的结果仍依赖该设置,容易混淆。
实操建议:
- 先确认当前
DATEFIRST:执行SELECT @@DATEFIRST;若需周一为第一天,开头加SET DATEFIRST 1 - 查指定年份+周数(如2024年第15周)的周一:
DATEADD(day, 2 - DATEPART(weekday, DATEFROMPARTS(2024,1,1)), DATEFROMPARTS(2024,1,1))再加周偏移 —— 更稳妥的是用DATEADD(week, 15-1, DATEADD(day, 1-DATEPART(weekday, '2024-01-01'), '2024-01-01')) - 避免用
DATEPART(week, ...)直接比对,它在跨年时可能返回1(比如2023-12-31可能是2024年第1周)
MySQL 没有内置 DATE_TRUNC('week'),得靠 DAYOFWEEK 和 DATE_SUB
MySQL 8.0+ 支持 DATE_TRUNC,但只接受 second/minute/hour/day 级别,'week' 会报错 ER_INVALID_ARGUMENT_FOR_FUNCTION。必须手动计算。
实操建议:
- 假设以周一为每周开始:
DATE_SUB(d, INTERVAL WEEKDAY(d) DAY)(WEEKDAY()周一=0,周日=6) - 若要 ISO 周(含第1周逻辑),需先用
YEARWEEK(d, 1)提取年+周,再用STR_TO_DATE(CONCAT(yw DIV 100, ' ', yw % 100, ' Monday'), '%X %v %W')构造周一日期 - 注意
WEEK()函数有 10 种模式(mode 参数),WEEK(d, 1)才是周一为第一天、第1周含4天以上的一周
跨数据库统一写法几乎不存在,别硬套一个函数名
同一个“第20周”在不同库、不同设置下指向的日期范围可能差整整7天。比如 2024-05-13(周一)在 PostgreSQL(DATE_TRUNC('week',...))中属于 2024-05-12 这周,但在 SQL Server 默认 DATEFIRST 7 下,DATEPART(week, '2024-05-13') 可能返回21而非20。
真正可靠的做法是:
- 明确业务要求:是否必须 ISO 8601?是否允许跨年周?周一起始还是周日起始?
- 在应用层生成目标周的起止日期(如用 Python 的
datetime.isocalendar()),再作为参数传入 SQL —— 比在 SQL 里拼逻辑更可控 - 如果必须纯 SQL,每个数据库单独实现,并加注释说明所采用的周定义,别指望
DATE_TRUNC或DATEPART自动适配你的业务语义

















