如何通过年份和周数获取对应周一日期(避免依赖1900-01-01)
解决方案:通过年份和周数获取对应周的周一日期
旧查询的问题分析
你当前的查询依赖1900-01-01(一个周一)作为基准,但每年的1月1日不一定是周一,直接按周数偏移会导致起始日偏差。比如2022年1月1日是周六,旧方法计算出的第50周起始日是周六(12月10日),而非你需要的周一(12月12日)。
不依赖固定基准日期的正确写法
以下是主流SQL数据库的实现,完全基于目标年份的日期计算,不依赖1900-01-01:
SQL Server
DECLARE @yearnum INT = 2022, @weeknum INT = 50; -- 计算当年的第一个周一 DECLARE @FirstMonday DATE = DATEADD(day, CASE DATEPART(weekday, DATEFROMPARTS(@yearnum, 1, 1)) WHEN 1 THEN 1 -- 1月1日是周日,加1天到周一 WHEN 2 THEN 0 -- 1月1日本身是周一 ELSE 2 - DATEPART(weekday, DATEFROMPARTS(@yearnum, 1, 1)) END, DATEFROMPARTS(@yearnum, 1, 1) ); -- 偏移到目标周的周一 SELECT DATEADD(week, @weeknum - 1, @FirstMonday) AS MondayOfTargetWeek;
如果你的业务遵循ISO周规则(周一为起始,第一周包含当年至少4天),可以用更简洁的写法:
DECLARE @yearnum INT = 2022, @weeknum INT = 50; SELECT DATEADD(day, 1 - DATEPART(weekday, iso_week_start), iso_week_start) AS MondayOfWeek FROM ( SELECT DATEADD(week, @weeknum - 1, DATEFROMPARTS(@yearnum, 1, 4)) AS iso_week_start ) t;
MySQL
如果按“每年第一周为包含1月1日的周,周一为周起始”:
SET @yearnum = 2022, @weeknum = 50; -- 计算目标周的起始日期,再调整到周一 SELECT DATE_ADD( DATE_ADD(MAKEDATE(@yearnum, 1), INTERVAL (@weeknum - 1) WEEK), INTERVAL (1 - DAYOFWEEK(DATE_ADD(MAKEDATE(@yearnum, 1), INTERVAL (@weeknum - 1) WEEK))) DAY ) AS MondayOfWeek;
遵循ISO周规则的话,直接用字符串构造:
SET @yearnum = 2022, @weeknum = 50; SELECT STR_TO_DATE(CONCAT(@yearnum, 'W', LPAD(@weeknum, 2, '0'), '1'), '%X%V%w') AS MondayOfWeek;
PostgreSQL
遵循ISO周规则的写法最直接:
SELECT to_date(concat(2022, ' ', 50, ' ', 1), 'IYYY IW ID') AS monday_of_week;
参数说明:IYYY=ISO年,IW=ISO周,ID=ISO周内的天数(1=周一)。
内容的提问来源于stack exchange,提问作者hdeguzm
相关产品推荐
相关产品推荐

