目录

Python计算日历星期

我们经常会在日历中看到本周是今年的第几周,这是如何定义的?又如何用 Python 来计算呢?

日历星期的定义

国标《GB/T 7408-2005》和 ISO 标准《ISO 8601-2004》中关于日历周的定义是一致的。主要包括:

参考点

日历星期的参考点为,把 2000 年 1 月 1 日定为星期六。

weekdays 编号

日历星期从星期一开始,编号为 01;至星期日结束,编号为 07。

日历星期数

  • 日历年中的日历星期由日历星期数标识。
  • 一年中的第一个日历星期包括该年的第一个星期四,且日历年中的最后一个日历星期就是下一个日历年的第一个日历星期之前的星期。日历星期数是其在该年中的顺序。
  • 一个日历年中有52或53个日历星期。

注意⚠️:也可以这样判断——一年中的第一个日历星期是包含 1 月 4 日的那个星期

Python模块

在 Python 中处理日历星期的标准库模块有 datetimecalendar

datetime

1
2
3
4
5
6
7
import datetime

# 东八区,中国标准时
timezone_cst = datetime.timezone(offset=datetime.timedelta(hours=8))

new_year = datetime.date(2000, 1, 1)
now = datetime.datetime.now(tz=timezone_cst)    # 2020-11-12

isoweekday()

isoweekday() 方法获取 weekdays 编号

1
new_year.isoweekday()   # 6
1
now.isoweekday()    # 4

isocalendar()

isocalendar() 方法返回三元组,(ISO year, ISO week number, ISO weekday)

1
new_year.isocalendar()      # (1999, 52, 6)

由于 2020-1-1 是周六,它的下一个周才包含周四,因此 2020-1-1 属于 1999 年的第 52 周。

1
now.isocalendar()       # (2020, 46, 4)

calendar

calendar 模块中的 weekday() 函数返回的是星期日编号是0-6,而不是1-7。

1
2
3
import calendar

calendar.weekday(2000, 1, 1)    # 5

示例

计算给定时间所在星期的起止时间

  1. 计算给定时间的 weekdays 编号;
  2. 根据 weekdays 编号计算星期一的日期,进而计算得到起始时间;
  3. 根据起始时间计算终止时间;

datetime.datetime.combine(date, time)可以将date对象和time对象合并为一个datetime对象。如果date对象参数传入了datetime类型对象,该对象的时间部分和时区部分将会被忽略。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import datetime

def get_week_by_time(given_time):
    weekday_num = given_time.isoweekday()
    # combine(星期一的日期, 零时, 给定时间的时区)
    week_start = datetime.datetime.combine(
        given_time - datetime.timedelta(days=weekday_num-1),
        datetime.time(),
        tzinfo=given_time.tzinfo
    )
    week_end = week_start + datetime.timedelta(weeks=1)
    return week_start, week_end


timezone_cst = datetime.timezone(offset=datetime.timedelta(hours=8))
now = datetime.datetime.now(tz=timezone_cst)
week_start, week_end = get_week_by_time(now)

print(now)
print(week_start)
print(week_end)

输出

1
2
3
2020-11-12 09:13:06.840023+08:00
2020-11-09 00:00:00+08:00
2020-11-16 00:00:00+08:00

给定年份和日历星期数,计算该星期的起止时间

根据日历星期的定义,每一年的 1 月 4 日肯定在这一年的第一个日历星期中。

  1. 计算给定年份 1 月 4 日的 weekdays 编号;
  2. 计算今年第一个日历星期的开始日期;
  3. 根据日历星期数差,计算给定日历星期数的起始日期,进而计算的到起始时间;
  4. 根据起始时间计算终止时间;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import datetime

def get_week_by_weeknum(year, weeknum, tzinfo=None):
    # 组装1月4日的日期
    day_jan_4th = datetime.date(year, 1, 4)
    # 今年第一个日历星期的开始日期
    first_week_start = day_jan_4th - datetime.timedelta(days=day_jan_4th.isoweekday()-1)
    # 所求星期的开始时间
    week_start = datetime.datetime.combine(
        first_week_start + datetime.timedelta(weeks=weeknum-1),
        datetime.time(),
        tzinfo=tzinfo,
    )
    week_end = week_start + datetime.timedelta(weeks=1)
    return week_start, week_end


timezone_cst = datetime.timezone(offset=datetime.timedelta(hours=8))

week_start, week_end = get_week_by_weeknum(2020, 46, tzinfo=timezone_cst)
print(week_start)
print(week_end)

输出

1
2
2020-11-09 00:00:00+08:00
2020-11-16 00:00:00+08:00

参考链接