SQLite中如何正确获取符合ISO-8601标准的周数?
如何在SQLite中正确获取符合ISO-8601标准的周数
确实,SQLite自带的STRFTIME('%W')并不遵循ISO-8601的周规则——它默认以周日为一周起始,且把每年1月1日所在的周算作第0周(或第1周,取决于年份),这就导致像2018-12-31这类边缘日期计算出错。要拿到完全符合标准的ISO周(包含正确的年份和周数),我们可以通过ISO周的核心规则来构建查询:
先明确ISO周的核心规则
要搞对计算逻辑,得先记住ISO周的两个关键:
- 一周的第一天是周一,不是周日
- 每年的第1周是当年第一个包含周四的周——这意味着:
- 如果1月1日是周一到周四,那它属于当年第1周
- 如果1月1日是周五到周日,它会被归到上一年的最后一周
- 同理,年末的几天可能属于下一年的第1周(比如你提到的2018-12-31)
正确的SQL查询语句
下面这个查询可以精准返回ISO标准的年份和周数,还能合并成YYYY-WW的规范格式:
SELECT -- 获取ISO年份 strftime('%Y', date('2018-12-31', '-3 days', 'weekday 4')) AS iso_year, -- 获取ISO周数(带两位数字格式) printf('%02d', (strftime('%j', date('2018-12-31', '-3 days', 'weekday 4')) - 1) / 7 + 1) AS iso_week, -- 合并成年份-周数的标准格式 strftime('%Y', date('2018-12-31', '-3 days', 'weekday 4')) || '-W' || printf('%02d', (strftime('%j', date('2018-12-31', '-3 days', 'weekday 4')) - 1) / 7 + 1) AS iso_week_full;
针对2018-12-31执行这个查询,会得到:
iso_year:2019iso_week:01iso_week_full:2019-W01
完全符合ISO-8601的要求。
拆解一下这个逻辑为什么有效
我们一步步看每个部分的作用:
date('2018-12-31', '-3 days', 'weekday 4'):- 在SQLite的
date函数里,weekday 4代表周四(取值规则是0=周日,1=周一,…,4=周四) - 先把目标日期减3天,再调整到最近的周四。这一步的核心是找到当前日期所在ISO周的周四——根据ISO规则,周四所在的年份就是这个ISO周对应的年份,完美解决跨年周的归属问题。
- 在SQLite的
- 计算ISO年份:直接取这个周四的年份,就是当前日期所属的ISO年,不会出错。
- 计算ISO周数:
strftime('%j', ...)获取该周四是当年的第几天(范围1-366)- 减1后除以7取整(整数除法),再加1,就能得到该周四所在的周数,也就是当前日期的ISO周数。
- 用
printf('%02d', ...)是为了让周数保持两位数字(比如第1周显示为01),严格遵循ISO格式的要求。
测试几个边界案例验证
可以用这些边缘日期测试,确保逻辑正确:
2019-01-01(周二):返回2019-W01,正确2020-12-31(周四):返回2020-W53,正确2021-01-01(周五):返回2020-W53,正确2023-12-31(周日):返回2024-W01,正确
内容的提问来源于stack exchange,提问作者shashank s
相关产品推荐
相关产品推荐

