数据库存非标准格式日期时,如何用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
相关产品推荐
相关产品推荐

