每周三触发的跨月生日查询功能异常排查求助
问题:跨月时无法查询到月底和月初的生日用户
我有一个每周三自动触发的功能,用于检查下周是否有过生日的用户。但当当月在周中结束时,需要该功能同时查询当月月底与下月初的生日记录,然而它无法正常工作——目前有两位用户分别在当月月底和下月初过生日,预期函数能返回这两位用户,但实际未返回任何结果。
代码如下:
async def find_bithday(): today = datetime.today().date() start_day = today + timedelta(days=5) end_day = start_day + timedelta(days=7) print(start_day, end_day) async with session() as sess: bithday_all = await sess.execute( select( Vip_Clients.full_name, Vip_Clients.address, Vip_Clients.phone, Vip_Clients.birthday ).where( extract('day', Vip_Clients.birthday) >= extract('day', start_day), extract('day', Vip_Clients.birthday) < extract('day', end_day), and_( or_( extract('month', Vip_Clients.birthday) == extract('month', start_day) ), or_( extract('month', Vip_Clients.birthday) == extract('month', end_day) ) ) ) ) return bithday_all.all()
问题分析与修复
你的代码在跨月场景下存在两个核心逻辑错误:
日期范围判断矛盾
当start_day是当月月底(比如12月28日)、end_day是下月初(1月4日)时,extract('day', start_day)为28,extract('day', end_day)为4。此时extract('day', birthday) >=28 AND <4的条件永远无法成立——月底用户的生日日(比如30)满足>=28但不满足<4,月初用户的生日日(比如2)满足<4但不满足>=28,自然查不到结果。月份条件逻辑错误
原代码用and_包裹两个or_完全冗余且逻辑错误,相当于要求生日月份同时等于start_day和end_day的月份,这在跨月场景下根本不可能实现。
修复方案
我们可以把用户的生日(仅保留月日部分)转换为当年的日期,直接判断该日期是否落在[start_day, end_day)区间内,这样不管是否跨月,逻辑都能正确生效。
修改后的代码如下:
from sqlalchemy import func, extract async def find_birthday(): # 修复原函数名拼写错误:bithday → birthday today = datetime.today().date() start_day = today + timedelta(days=5) end_day = start_day + timedelta(days=7) print(start_day, end_day) current_year = extract('year', func.current_date()) async with session() as sess: # 将用户生日转换为当年的日期(忽略原生日年份) birthday_this_year = func.date( current_year, extract('month', Vip_Clients.birthday), extract('day', Vip_Clients.birthday) ) birthday_all = await sess.execute( select( Vip_Clients.full_name, Vip_Clients.address, Vip_Clients.phone, Vip_Clients.birthday ).where( birthday_this_year >= start_day, birthday_this_year < end_day ) ) return birthday_all.all()
数据库兼容说明
如果你的数据库是MySQL,需要把func.date替换为func.str_to_date,示例如下:
birthday_this_year = func.str_to_date( func.concat(current_year, '-', extract('month', Vip_Clients.birthday), '-', extract('day', Vip_Clients.birthday)), '%Y-%m-%d' )
内容的提问来源于stack exchange,提问作者Egor
相关产品推荐
相关产品推荐

