tl;博士
“ISO 标准”和“您想要什么”部分是为了阐明您的需求。
您可以将代码复制粘贴到“解决方案”部分,看看结果是否符合您的要求。
ISO 标准
定义
- 每周从星期一开始。
- 每周的年份都是公历,星期四所在的年份。
Python 标准库的结果datetime
>>> datetime(2020, 1, 1).isocalendar()
(2020, 1, 3) # The 3rd day of the 1st week in 2020
>>> datetime(2019, 12, 31).isocalendar()
(2020, 1, 2) # The 2nd day of the 1st week in 2020
>>> datetime(2019, 1, 1).isocalendar()
(2019, 1, 2)
>>> datetime(2017, 1, 1).isocalendar()
(2016, 52, 7)
>>> datetime(2016, 12, 26).isocalendar()
(2016, 52, 1)
>>> datetime(2015, 12, 31).isocalendar()
(2015, 53, 4)
>>> datetime(2016, 1, 1).isocalendar()
(2015, 53, 5)
日历草图
# Mo Tu Wd Th Fr Sa Sn
# [2019-52w] DEC/ 23 24 25 26 27 28 29 /DEC
# [2020-1w] DEC/ 30 31 1 2 3 4 5 /JAN
# [2019-1w] DEC/ 31 1 2 3 4 5 6 /JAN
# [2016-52w] DEC/ 26 27 28 29 30 31 1 /JAN
# [2015-53w] DEC/ 28 29 30 31 1 2 3 /JAN
# [2016-1w] JAN/ 4 5 6 7 8 9 10 /JAN
你想要什么
定义
- 每周从星期五开始。
- 每周的年份都是公历年,星期一所在的年份。
日历草图
# Fr Sa Sn. Mo Tu Wd Th
# [2019-51w] DEC/ 20 21 22. 23 24 25 26 /DEC
# [2019-52w] DEC/ 27 28 29. 30 31 1 2 /JAN
# [2020-1w] JAN/ 3 4 5. 6 7 8 9 /JAN
# [2018-53w] DEC/ 28 29 30. 31 1 2 3 /JAN
# [2019-1w] JAN/ 4 5 6. 7 8 9 10 /JAN
# [2016-52w] DEC/ 23 24 25. 26 27 28 29 /DEC
# [2017-1w] DEC/ 30 31 1. 2 3 4 5 /JAN
# [2015-52w] DEC/ 25 26 27. 28 29 30 31 /DEC
# [2016-1w] JAN/ 1 2 3. 4 5 6 7 /JAN
解决方案
from datetime import datetime, timedelta
from enum import IntEnum
WEEKDAY = IntEnum('WEEKDAY', 'MON TUE WED THU FRI SAT SUN', start=1)
class CustomizedCalendar:
def __init__(self, start_weekday, indicator_weekday=None):
self.start_weekday = start_weekday
self.indicator_delta = 3 if not (indicator_weekday) else (indicator_weekday - start_weekday) % 7
def get_week_start(self, date):
delta = date.isoweekday() - self.start_weekday
return date - timedelta(days=delta % 7)
def get_week_indicator(self, date):
week_start = self.get_week_start(date)
return week_start + timedelta(days=self.indicator_delta)
def get_first_week(self, year):
indicator_date = self.get_week_indicator(datetime(year, 1, 1))
if indicator_date.year == year: # The date "year.1.1" is on 1st week.
return self.get_week_start(datetime(year, 1, 1))
else: # The date "year.1.1" is on the last week of "year-1".
return self.get_week_start(datetime(year, 1, 8))
def calculate(self, date):
year = self.get_week_indicator(date).year
first_date_of_first_week = self.get_first_week(year)
diff_days = (date - first_date_of_first_week).days
return year, (diff_days // 7 + 1), (diff_days % 7 + 1)
if __name__ == '__main__':
# Use like this:
my_calendar = CustomizedCalendar(start_weekday=WEEKDAY.FRI, indicator_weekday=WEEKDAY.MON)
print(my_calendar.calculate(datetime(2020, 1, 2)))
测试
我们可以简单地用原始 ISO 设置初始化CustomizedCalendar,并验证结果是否与原始isocalendar() 的结果相同。
my_calendar = CustomizedCalendar(start_weekday=WEEKDAY.MON)
s = datetime(2019, 12, 19)
for delta in range(20):
print my_calendar.calculate(s) == s.isocalendar()
s += timedelta(days=1)