问题
4.编写处理如下日期的函数:给定两个日期,计算两者之间的天数;给定一个日期,返回值为周几;给定月和年,使用字符数组生成该月的日历。
思路
分为三个小问
第一问
计算日期差,我们用图来解释具体计算逻辑
如图所示,d1, d2之差为绿色画线部分。我们从年份的角度入手,上图可以划分为三块:d1所在年份,中间年份,d2所在年份
具体计算逻辑如下
d1年剩下天数 + 中间年份包含天数 + d2所在年份经历的天数
计算天数的时候,需要将闰年因素考虑进去,也就是对最终计算结果增加修正逻辑
第二问
返回周几?
这一问就简单很多了,我们只需要计算当前日期经历的天数,然后对7整除,即可得到本周是周几
第三问
返回数组,生成日历
生成日历的关键点,就是弄清楚本月第一天是周几。弄清楚这一点后,创建数组时,添加额外的元素,直到月初第一天排序到正确的下标,表示正确的星期几即可
代码
简单说一下代码思路,为了更方便编写,做了一些抽象
Timer抽象出Calendar,Date共有的一些方法和变量
Date用于表示日期,其中包含一些处理日期的方法
Calendar用于处理日期与日期之间关系,并对日期做出更为复杂的处理。Calendar包含的三个方法,直接对应题目要求的三个问题
'''
时间基类
'''
class Timer:
month_day = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def __init__(self):
pass
@staticmethod
def is_leap_year(year):
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
return True
else:
return False
'''
日期类, 继承时间类
'''
class Date(Timer):
def __init__(self, year: int, month: int, day: int):
super().__init__() # 调用父类的构造函数
self.year = year
self.month = month
self.day = day
'''
转化为天数
'''
def day_convert(self) -> int:
if self.month == 1:
return self.day
if self.month == 2:
return 31 + self.day
day = sum(Timer.month_day[0:self.month - 1]) + self.day
# 如果是闰年, + 1
return day + (1 if Timer.is_leap_year(self.year) else 0)
'''
年做差
'''
def year_diff(self, d2: 'Date') -> int:
return self.year - d2.year
'''
获取当前日期所在week的day
'''
def get_week_day(self) -> int:
days = self.day_convert()
week_day = days % 7
return 7 if week_day == 0 else week_day
'''
获取当前月份的天数
'''
def get_day_count_of_month(self) -> int:
day_count = Timer.month_day[self.month - 1]
return day_count + (1 if Timer.is_leap_year(self.month) else 0)
'''
日历类, 继承时间类
'''
class Calendar(Timer):
def __init__(self):
super().__init__() # 调用父类的构造函数
@staticmethod
def day_bigger(d1: Date, d2: Date) -> int:
day1, day2 = d1.day_convert() + d1.year * 365, d2.day_convert() + d2.year * 365
if day1 > day2:
return 1
elif day1 < day2:
return -1
else:
return 0
'''
获取日期之差
'''
def day_diff(self, date1: Date, date2: Date) -> int:
# 日月转换
_d1, _d2 = date1, date2
bigger_flag = Calendar.day_bigger(_d1, _d2)
if bigger_flag == -1:
_d1, _d2 = _d2, _d1
day1, day2 = _d1.day_convert(), _d2.day_convert()
# 年做差
year_diff = _d1.year_diff(_d2)
days = 0
if _d1.year == _d2.year:
days = day1 - day2
else:
# 计算核心逻辑: _d1年剩下天数 + 中间年份包含天数 + _d2所在年份经历的天数
days = (Date(_d2.year, 12, 31).day_convert() - day2) + (year_diff - 1) * 365 + day1
# 修正
for year in range(_d1.year + 1, _d2.year):
if self.is_leap_year(year):
days += 1
return -days if bigger_flag == -1 else days
'''
获取当前日期所在week
'''
@staticmethod
def get_week(d: Date) -> int:
days = d.day_convert()
return days // 7 + (0 if days % 7 == 0 else 1)
@staticmethod
def print_month(year, month):
d = Date(year, month, 1)
week_day = d.get_week_day()
week_list = ['' for _ in range(week_day - 1)]
for day in range(1, d.get_day_count_of_month() + 1):
week_list.append(day)
# 处理成二维数组
row_count = len(week_list)//7 + (1 if len(week_list) % 7 != 0 else 0)
res = [week_list[i * 7:(i * 7) + 7] for i in range(row_count)]
for row in res:
print(row)
测试
测试代码使用python自带的时间模块检验编写代码的正确性。如果使用我编写的时间模块计算得到的答案和python自带的时间模块得到的答案相同,那么说明我编写的代码没有问题
def test_day_diff():
from datetime import datetime
# 定义两个日期字符串
date_str1 = "2020-02-10"
date_str2 = "2024-01-30"
# 将字符串转换为datetime对象
date_format = "%Y-%m-%d"
date1 = datetime.strptime(date_str1, date_format)
date2 = datetime.strptime(date_str2, date_format)
# 计算两个日期之间的差值
delta = date1 - date2
# 输出日期差值
print("两个日期相差:", delta.days, "天")
d1 = Date(2020, 2, 10)
d2 = Date(2024, 1, 30)
c = Calendar()
print(c.day_diff(d1, d2))
def test_get_week():
from datetime import datetime
# 定义日期字符串
date_str = "2024-09-09"
# 设置日期格式
date_format = "%Y-%m-%d"
# 将字符串转换为datetime对象
date_obj = datetime.strptime(date_str, date_format)
# 使用isocalendar()方法获取ISO周数
year, week_num, _ = date_obj.isocalendar()
# 输出结果
print(f"{date_str} 是 {year} 年的第 {week_num} 周。")
d1 = Date(2024, 9, 9)
c = Calendar()
print(c.get_week(d1))
def test_print_month():
Calendar.print_month(2024, 9)
test_day_diff()
test_get_week()
test_print_month()
正确!