案例目的
能正确检查闰年情况(如2020年2月有29天)和各月份的不同天数(28-31天),并包含必要的错误处理。
V1.0
from datetime import datetime, timedelta
def check_last_day(date_str):
try:
# 将字符串解析为日期对象
input_date = datetime.strptime(date_str, "%Y%m%d")
# 计算输入日期所在月份的下个月第一天
if input_date.month == 12:
next_month = input_date.replace(year=input_date.year+1, month=1, day=1)
else:
next_month = input_date.replace(month=input_date.month+1, day=1)
# 计算当月的最后一天(下个月第一天减去1天)
last_day_of_month = next_month - timedelta(days=1)
# 检查输入日期是否是当月最后一天
if input_date.date() != last_day_of_month.date():
print(f"Warning: {date_str} is not the last day of the month.")
except ValueError:
print(f"Error: Invalid date format or value: {date_str}")
函数说明
- 输入处理:使用 datetime.strptime 将格式为 YYYYMMDD 的字符串解析为日期对象
- 计算当月最后一天:
- 计算输入日期下个月的第一天
- 减去1天得到当月的最后一天
- 检查逻辑:
- 如果输入日期等于计算出的当月最后一天 → 无输出
- 如果不是最后一天 → 打印警告信息
- 错误处理:
- 无效日期格式或非法日期值(如20251301)会触发异常并打印错误信息
V2.0
from datetime import datetime, timedelta
def check_last_day(date_str):
try:
input_date = datetime.strptime(date_str, "%Y%m%d")
year, month = input_date.year, input_date.month
# 计算当前月份的最后一天
if month == 12:
last_day = datetime(year, 12, 31)
else:
next_month = datetime(year, month + 1, 1)
last_day = next_month - timedelta(days=1)
# 直接比较日期对象
if input_date != last_day:
print(f"Warning: {date_str} is not the last day of the month.")
except ValueError:
print(f"Error: Invalid date format or value: {date_str}")
优化点说明:
- 减少对象创建:直接通过年份和月份计算最后一天,避免创建多余的日期对象。
- 简化逻辑:对于12月直接使用固定日期,其他月份通过计算下月第一天再减去一天得到最后一天。
- 直接比较:使用
datetime对象直接比较,避免转换为date对象,减少转换开销。
进一步优化(避免创建next_month对象):
from datetime import datetime, timedelta
def check_last_day(date_str):
try:
input_date = datetime.strptime(date_str, "%Y%m%d")
year, month = input_date.year, input_date.month
if month == 12:
last_day = datetime(year, 12, 31)
else:
# 计算当前月份的最后一天(通过下月第一天减1天)
last_day = datetime(year, month + 1, 1) - timedelta(days=1)
if input_date != last_day:
print(f"Warning: {date_str} is not the last day of the month.")
except ValueError:
print(f"Error: Invalid date format or value: {date_str}")
V3.0
import calendar
from datetime import datetime
def check_last_day(date_str):
try:
input_date = datetime.strptime(date_str, "%Y%m%d")
year, month = input_date.year, input_date.month
_, last_day = calendar.monthrange(year, month)
if input_date.day != last_day:
print(f"Warning: {date_str} is not the last day of the month.")
except ValueError:
print(f"Error: Invalid date format or value: {date_str}")
最终优化的优点:
- 最高效:使用
calendar.monthrange直接获取月份天数,无需创建任何额外日期对象。 - 最简洁:逻辑清晰,代码量少,直接比较日期中的天数部分。
- 内存占用最低:仅使用基本整数比较,无额外时间对象操作。
V3.1
import calendar
from datetime import datetime
def check_last_day(date_str):
try:
input_date = datetime.strptime(date_str, "%Y%m%d")
year, month = input_date.year, input_date.month
_, last_day = calendar.monthrange(year, month)
if input_date.day != last_day:
# 创建正确的月末日期
correct_date = datetime(year, month, last_day)
correct_date_str = correct_date.strftime("%Y%m%d")
print(f"Warning: {date_str} is not the last day of the month.")
return correct_date_str
else:
# print(f"{date_str} is the last day of the month.")
return date_str # 或者返回 None return None
except ValueError:
print(f"Error: Invalid date format or value: {date_str}")
return None
V4.0
添加类型注解(-> str)本身不会直接影响内存使用,因为类型注解在运行时会被忽略(Python 3.5+ 的特性注解不会影响性能)。
import calendar
def check_last_day(date_str: str) -> str:
"""检查日期是否为月末,如果不是则返回正确的月末日期"""
if len(date_str) != 8 or not date_str.isdigit():
print(f"Error: Invalid date format: {date_str}")
return ""
year, month, day = int(date_str[:4]), int(date_str[4:6]), int(date_str[6:8])
# 验证月份有效性
if not 1 <= month <= 12:
print(f"Error: Invalid month in date: {date_str}")
return ""
# 获取月份的最后一天
_, last_day = calendar.monthrange(year, month)
# 验证日期有效性
if not 1 <= day <= last_day:
print(f"Error: Invalid day in date: {date_str}")
return ""
if day != last_day:
# 直接构建正确的日期字符串,避免创建datetime对象
correct_date = f"{year:04d}{month:02d}{last_day:02d}"
print(f"Warning: {date_str} is not the last day of the month.")
return correct_date
else:
print(f"{date_str} is the last day of the month.")
return date_str
这个优化版本的优点:
- 避免创建datetime对象:直接使用字符串操作和整数计算,减少内存分配
- 更早的错误检测:先检查格式和基本有效性,避免不必要的计算
- 更精确的错误处理:分别处理格式错误、月份无效和日期无效的情况
- 添加类型注解:提高代码可读性和可维护性(虽然不影响运行时性能)
这个版本在处理大量日期时会更加高效,特别是在内存使用方面,因为它避免了创建不必要的datetime对象。
735

被折叠的 条评论
为什么被折叠?



