import datetime
from typing import List, Dict
class WeekUtils:
"""周次工具类,提供周次计算相关方法"""
@staticmethod
def get_weeks_of_year(year: int) -> List[str]:
"""
获取指定年份的所有周次列表,格式为 [YYYY-WW]
规则:以周日作为周的最后一天,跨年周归属以周日所在年份为准
:param year: 目标年份(如 2024)
:return: 周次列表(如 ["2024-01", "2024-02", ...])
"""
weeks = []
date = datetime.date(year, 1, 1)
while date.weekday() != 5:
date += datetime.timedelta(days=1)
week_num = 1
while date.year == year:
week_str = f"{year}-{week_num:02d}"
weeks.append(week_str)
date += datetime.timedelta(weeks=1)
week_num += 1
return weeks
@staticmethod
def get_week_by_date(date: datetime.datetime) -> str:
"""
按日期获取周次--周日为每周第一天--判断周六所在年份/月份为周次归属年份/月份
如:2025/12/31为2026-01
:param date: 日期对象
:return: 周次字符串(如 "2025-01")
"""
year = date.year
week_date = datetime.datetime(year, 1, 1)
while week_date.weekday() != 5:
week_date += datetime.timedelta(days=1)
week_num = 1
while week_date.year == year:
if date <= week_date:
return f"{year}-{week_num:02d}"
week_date += datetime.timedelta(weeks=1)
week_num += 1
return f"{year + 1}-01"
@staticmethod
def get_loose_iso_week_number(date: datetime.date) -> str:
"""
获取符合ISO框架但放宽第一周限制的周次(周一开始,第一周只需包含1天)
:param date: 需要计算的日期
:return: 周次字符串(如 "WK01")
"""
year_start = datetime.date(date.year, 1, 1)
start_weekday = year_start.weekday()
days_diff = (date - year_start).days
week_num = (days_diff + start_weekday) // 7 + 1
return f"WK{week_num:02d}"
@staticmethod
def get_loose_iso_week_based_year(date: datetime.date) -> str:
"""
获取包含年份的完整周次标识(如2024-W53)
:param date: 需要计算的日期
:return: 符合宽松ISO格式的年份周次
"""
year = date.year
jan_first = datetime.date(year, 1, 1)
if date < jan_first and date.weekday() < 4:
year -= 1
year_start = datetime.date(year, 1, 1)
start_weekday = year_start.weekday()
days_diff = (date - year_start).days
week_num = (days_diff + start_weekday) // 7 + 1
return f"{year:04d}-W{week_num:02d}"
@staticmethod
def get_week_range(week_based_year: int, week_number: int) -> Dict[str, datetime.date]:
"""
获取指定周次的日期范围(周一开始,共7天)
:param week_based_year: 基于周的年份
:param week_number: 周次(从1开始)
:return: 包含start和end的字典,跨度为7天
"""
first_day = datetime.date(week_based_year, 1, 1)
while first_day.weekday() != 0:
first_day -= datetime.timedelta(days=1)
start = first_day + datetime.timedelta(weeks=week_number - 1)
end = start + datetime.timedelta(days=6)
return {
"start": start,
"end": end
}