
TLDR:
- ISO 8601 标准:国际标准规定周一为一周的开始,包含 1 月 4 日的那一周为第一周
- Java: 使用
WeekFields.ISO获取 ISO 标准周数,或使用本地化设置 - Python: 使用
strftime的%W(本地化) 或%V(ISO) 参数获取周数 - Go: 使用
ISOWeek()方法获取 ISO 标准周数 - MySQL: 使用
WEEK()函数的 mode 3 或 7 获取 ISO 标准周数
Java
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class WeekNumberExample {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2021, 1, 1);
// 使用 ISO 标准计算周数(周一为一周开始)
int weekNumber = date.get(WeekFields.ISO.weekOfYear());
System.out.println("ISO week number: " + weekNumber);
// 使用本地化周数计算
WeekFields weekFields = WeekFields.of(Locale.getDefault());
int localizedWeek = date.get(weekFields.weekOfYear());
System.out.println("Localized week number: " + localizedWeek);
}
}
Python
import datetime
# 说明不同格式化参数的含义:
# %Y - 年份 (基于日历年度)
# %W - 周数 (周一作为一周的开始,第一周是包含第一个周一的周)
# %G - 年份 (基于ISO周数)
# %V - 周数 (ISO周数,周一作为一周开始,第一周是包含1月4日的那一周)
for i in range(10):
d = datetime.date(2021 - i, 1, 1)
print((str(d), d.weekday(), d.strftime('%Y %W / %G %V')))
('2021-01-01', 4, '2021 00 / 2020 53')
('2020-01-01', 2, '2020 00 / 2020 01')
('2019-01-01', 1, '2019 00 / 2019 01')
('2018-01-01', 0, '2018 01 / 2018 01')
('2017-01-01', 6, '2017 00 / 2016 52')
('2016-01-01', 4, '2016 00 / 2015 53')
('2015-01-01', 3, '2015 00 / 2015 01')
('2014-01-01', 2, '2014 00 / 2014 01')
('2013-01-01', 1, '2013 00 / 2013 01')
('2012-01-01', 6, '2012 00 / 2011 52')
Go
package main
import (
"fmt"
"time"
)
func main() {
// Go 中计算周数
t := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
// 使用 ISO 标准计算周数
_, week := t.ISOWeek()
fmt.Printf("ISO week number: %d\n", week)
// 使用 YearDay 计算基于年的周数
yearDay := t.YearDay()
weekFromYearDay := (yearDay + 6) / 7
fmt.Printf("Week from year day: %d\n", weekFromYearDay)
}
MySQL 中的实现
WEEK(date[, mode]) 函数:
| Mode | First day of week | Range | Week 1 is the first week … |
|---|---|---|---|
| 0 | Sunday | 0-53 | with a Sunday in this year |
| 1 | Monday | 0-53 | with 4 or more days this year |
| 2 | Sunday | 1-53 | with a Sunday in this year |
| 3 | Monday | 1-53 | with 4 or more days this year |
| 4 | Sunday | 0-53 | with 4 or more days this year |
| 5 | Monday | 0-53 | with a Monday in this year |
| 6 | Sunday | 1-53 | with 4 or more days this year |
| 7 | Monday | 1-53 | with a Monday in this year |
总结一下,就是三个维度:
- 周数从 0 开始还是从 1 开始
- 以周一算每周的第一天还是周日
- 按每周第一天开始算,还是按每周四天开始算
0 周日 每周第一天 0
2 周日 每周第一天 1
4 周日 每周四天 0
6 周日 每周四天 1
1 周一 每周四天 0
3 周一 每周四天 1
5 周一 每周第一天 0
7 周一 每周第一天 1
SELECT NULL AS Mode, WEEK('2021-01-01'), WEEK('2021-01-04')
UNION SELECT 0 AS Mode, WEEK('2021-01-01', 0), WEEK('2021-01-04', 0)
UNION SELECT 1 AS Mode, WEEK('2021-01-01', 1), WEEK('2021-01-04', 1)
UNION SELECT 2 AS Mode, WEEK('2021-01-01', 2), WEEK('2021-01-04', 2)
UNION SELECT 3 AS Mode, WEEK('2021-01-01', 3), WEEK('2021-01-04', 3)
UNION SELECT 4 AS Mode, WEEK('2021-01-01', 4), WEEK('2021-01-04', 4)
UNION SELECT 5 AS Mode, WEEK('2021-01-01', 5), WEEK('2021-01-04', 5)
UNION SELECT 6 AS Mode, WEEK('2021-01-01', 6), WEEK('2021-01-04', 6)
UNION SELECT 7 AS Mode, WEEK('2021-01-01', 7), WEEK('2021-01-04', 7);
| Mode | WEEK('2021-01-01') | WEEK('2021-01-04') |
|---|---|---|
| NULL | 0 | 1 |
| 0 | 0 | 1 |
| 1 | 0 | 1 |
| 2 | 52 | 1 |
| 3 | 53 | 1 |
| 4 | 0 | 1 |
| 5 | 0 | 1 |
| 6 | 53 | 1 |
| 7 | 52 | 1 |
我定义的每周迭代名称(例如:2020-01A)
- 每周第一天为周一。
- 按照周一属于哪个月计算。
import datetime
from datetime import timedelta
def get_week_iteration_name(date):
"""
根据周一所属月份计算周迭代名称
格式:YYYY-MM{A-Z}
返回:str, date, date (迭代名称,周一日期,周日日期)
"""
weekday = date.weekday()
monday = date - timedelta(days=weekday)
sunday = monday + timedelta(days=6)
year = monday.year
month = monday.month
# 计算该月第几个周一
# 找到该月第一个周一
first_day = datetime.date(year, month, 1)
first_monday_offset = (7 - first_day.weekday()) % 7
first_monday = first_day + timedelta(days=first_monday_offset)
# 如果第一个周一不在本月,说明该月第一天就是周一
if first_monday.month != month:
first_monday = first_day
# 计算是第几个周一
week_index = ((monday - first_monday).days // 7) + 1
# 转换为字母标识 (A=1, B=2, ...)
week_letter = chr(ord('A') + week_index - 1)
return f"{year}-{month:02d}{week_letter}", monday, sunday
test_dates = [
datetime.date(2021, 1, 1), # Friday
datetime.date(2021, 1, 4), # Monday
datetime.date(2021, 1, 8), # Friday
datetime.date(2020, 12, 28), # Monday
]
for d in test_dates:
weekday = d.weekday()
name, monday, sunday = get_week_iteration_name(d)
print(f"{d} -> {name} {weekday + 1} (Mon: {monday}, Sun: {sunday})")