按时间范围筛选icalendar事件时datetime比较报错如何解决
问题解决:offset-naive与offset-aware datetime比较报错
问题根源
你遇到的TypeError: can't compare offset-naive and offset-aware datetimes报错核心原因是参与比较的三个时间now、start、next_month没有统一为带时区的datetime类型:
- 仅给
next_month设置了UTC时区,比较逻辑里用到的now没有定义也没有配置时区,属于无偏移的naive时间 - 从ics文件中读取的事件
start时间可能自带时区,和naive类型的时间直接比较就会触发类型错误
修复方案
对所有参与比较的时间做统一时区处理,修复后的代码如下:
import pytz from datetime import datetime from icalendar import Calendar def read_from_cal(): # 用with语句管理文件句柄,避免资源泄漏 with open('calendar.ics', 'rb') as g: gcal = Calendar.from_ical(g.read()) # 直接生成带UTC时区的当前时间,避免naive类型 now = datetime.now(pytz.UTC) # 处理12月跨年的月份溢出问题 if now.month == 12: next_month = datetime(now.year + 1, 1, now.day, now.hour, now.minute, 0, tzinfo=pytz.UTC) else: next_month = datetime(now.year, now.month + 1, now.day, now.hour, now.minute, 0, tzinfo=pytz.UTC) for component in gcal.walk(): if component.name == "VEVENT": summ = component.get('summary') start = component.get('dtstart').dt end = component.get('dtend').dt # 统一将ics读取的时间转为UTC时区的aware类型 if start.tzinfo is None or start.tzinfo.utcoffset(start) is None: # 原生无时区则补充UTC时区 start = start.replace(tzinfo=pytz.UTC) else: # 已有时区则转为UTC时区 start = start.astimezone(pytz.UTC) if now <= start <= next_month: print("Worked") print(summ, start, end)
额外说明
- 如果你需要用本地时区而非UTC做比较,把代码中所有的
pytz.UTC替换为你对应的时区对象即可,比如pytz.timezone('Asia/Shanghai') - 如果需要更简便的计算一个月后的时间,可以安装
python-dateutil库,用relativedelta处理:next_month = now + relativedelta(months=1),不需要手动处理跨年逻辑
内容的提问来源于stack exchange,提问作者greenbug
相关产品推荐
相关产品推荐

