You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

每周三触发的跨月生日查询功能异常排查求助

问题:跨月时无法查询到月底和月初的生日用户

我有一个每周三自动触发的功能,用于检查下周是否有过生日的用户。但当当月在周中结束时,需要该功能同时查询当月月底与下月初的生日记录,然而它无法正常工作——目前有两位用户分别在当月月底和下月初过生日,预期函数能返回这两位用户,但实际未返回任何结果。

代码如下:

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()

问题分析与修复

你的代码在跨月场景下存在两个核心逻辑错误:

  1. 日期范围判断矛盾
    当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,自然查不到结果。

  2. 月份条件逻辑错误
    原代码用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:10:34