Python 小技巧:时间校正函数(校正为当月最后一日)

案例目的

能正确检查闰年情况(如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}")

函数说明

  1. 输入处理:使用 datetime.strptime 将格式为 YYYYMMDD 的字符串解析为日期对象
  2. 计算当月最后一天:
    • 计算输入日期下个月的第一天
    • 减去1天得到当月的最后一天
  3. 检查逻辑:
    • 如果输入日期等于计算出的当月最后一天 → 无输出
    • 如果不是最后一天 → 打印警告信息
  4. 错误处理:
    • 无效日期格式或非法日期值(如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}")

优化点说明:

  1. 减少对象创建:直接通过年份和月份计算最后一天,避免创建多余的日期对象。
  2. 简化逻辑:对于12月直接使用固定日期,其他月份通过计算下月第一天再减去一天得到最后一天。
  3. 直接比较:使用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}")

最终优化的优点:

  1. 最高效:使用calendar.monthrange直接获取月份天数,无需创建任何额外日期对象。
  2. 最简洁:逻辑清晰,代码量少,直接比较日期中的天数部分。
  3. 内存占用最低:仅使用基本整数比较,无额外时间对象操作。

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

这个优化版本的优点:

  1. 避免创建datetime对象:直接使用字符串操作和整数计算,减少内存分配
  2. 更早的错误检测:先检查格式和基本有效性,避免不必要的计算
  3. 更精确的错误处理:分别处理格式错误、月份无效和日期无效的情况
  4. 添加类型注解:提高代码可读性和可维护性(虽然不影响运行时性能)

这个版本在处理大量日期时会更加高效,特别是在内存使用方面,因为它避免了创建不必要的datetime对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值