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

数据库存非标准格式日期时,如何用Eloquent实现订阅到期判断?

解决varchar格式日期的Eloquent对比问题

嘿,我明白你现在的困扰——用varchar存储了易读格式的日期(比如12th April 2018),但没法直接用Eloquent和Carbon做日期对比来筛选即将到期的订阅对吧?别担心,我给你几个实用的解决方案!

核心问题原因

数据库的varchar类型字段只是普通字符串,它没法识别12th April 2018这种格式的日期含义,所以直接用whereDate或者Carbon生成的日期字符串对比肯定会失效。我们需要先把这个字符串转换成数据库能识别的日期类型,再进行对比。

解决方案1:直接在查询中转换日期格式(快速实现)

如果你的数据库是MySQL,可以用内置的STR_TO_DATE()函数把存储的字符串日期转换成标准日期格式,然后再和Carbon生成的日期做对比。

筛选刚好130天后到期的订阅

$targetDate = Carbon::now()->addDays(130)->toDateString();

$expiredPacks = DB::table('subscriptions')
    ->whereRaw("STR_TO_DATE(expires_on, '%D %M %Y') = ?", [$targetDate])
    ->get();

这里的格式符%D对应带后缀的日期(比如1st、2nd、12th),%M对应月份全称(比如April),%Y对应四位年份,完美匹配你存储的日期格式。

筛选130天内即将到期的订阅

如果需要找从现在到130天后之间到期的订阅,可以用BETWEEN:

$today = Carbon::now()->toDateString();
$targetDate = Carbon::now()->addDays(130)->toDateString();

$expiredPacks = DB::table('subscriptions')
    ->whereRaw("STR_TO_DATE(expires_on, '%D %M %Y') BETWEEN ? AND ?", [$today, $targetDate])
    ->get();

解决方案2:长期优化方案(适合数据量大的场景)

虽然当前用varchar存储是为了易读,但从性能角度来说,用date或datetime类型存储日期是更优的选择。这样不仅能避免每次查询都要做格式转换(数据量大时会拖慢查询速度),还能直接使用Eloquent的日期快捷方法:

如果把expires_on字段改成date类型,代码会简洁很多:

// 假设你有Subscription模型
$expiredPacks = Subscription::whereDate('expires_on', '=', Carbon::now()->addDays(130))->get();

如果担心前端显示的可读性,完全可以在模型里定义访问器,把日期转换成12th April 2018这种格式输出:

// 在Subscription模型中添加
public function getExpiresOnAttribute($value)
{
    return Carbon::parse($value)->format('jS F Y');
}

这样数据库存储的是高效的date类型,前端显示的还是你想要的易读格式,一举两得。

内容的提问来源于stack exchange,提问作者Ibrahim Usman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:04:16