Python 3.8.3中ISO周格式(%V)异常:2019年首尾日均属第1周的原因
关于Python中ISO周格式(%V)的“异常”解析
哈哈,这个看起来矛盾的输出其实完全符合ISO 8601周编号标准的规则,可不是Python的bug哦!我来给你拆解清楚背后的逻辑:
先搞懂ISO周的核心规则
ISO 8601对周的定义有几个关键要点:
- 每周从周一开始,周日结束
- 第1周的判定标准:包含当年第一个周四的那一周(也可以等价理解为:包含1月4日的周,或者该周至少有4天属于当前日历年)
- 当某一周跨两年时,这一周属于“包含更多天数的那个年份”的周数
对应到你遇到的2019年情况
1. 2019年1月1日的输出(2019-W01)
2019年1月1日是周二,它所在的周是2018年12月31日(周一)到2019年1月6日(周日)。这一周里,2019年的天数有6天(周二到周日),远超过4天,同时也包含2019年1月4日,所以这一周被认定为2019年的第1周,输出2019-W01是完全正确的。
2. 2019年12月31日的输出(2019-W01)
这是最容易困惑的点:2019年12月31日是周二,它所在的周是2019年12月30日(周一)到2020年1月5日(周日)。这一周里,2020年的天数有5天(1月1日到1月5日),而2019年只有2天(12月30、31日),所以这一周实际上是2020年的第1周。
那为什么输出是2019-W01?问题出在你用的格式符:
%Y:取的是日期的日历年份(也就是2019年,因为12月31日确实在2019年的日历里)%V:取的是ISO周数(这一周是第1周,但属于2020年的第1周)
两者搭配就出现了“2019年的第1周”这种看似矛盾的表述——这其实是格式符搭配错误导致的不规范输出。
正确的ISO周年份格式符:%G
如果要输出符合ISO标准的完整周标识,应该用%G(ISO周对应的年份)代替%Y,这样就能得到正确的结果:
from datetime import date print(date(2019, 1, 1).strftime('%G-W%V')) # 输出:2019-W01 print(date(2019, 12, 29).strftime('%G-W%V')) # 输出:2019-W52 print(date(2019, 12, 31).strftime('%G-W%V')) # 输出:2020-W01
这样就完全符合ISO 8601的规范了,不会再出现看似矛盾的结果。
内容的提问来源于stack exchange,提问作者Charles R




