如何在指定时间后查询当日未重置的用户目标以重置进度?
实现基于用户自定义重置时间的Goal自动重置逻辑
我之前做过类似的定时重置任务,结合你的需求,整理了完整的实现代码和逻辑说明:
首先,假设你的goals表除了progress和reset_time,还应该有一个last_reset_at字段(用来记录最后一次重置的时间,判断当日是否已重置)——如果还没有的话,建议先加上这个字段,它能帮我们准确判断哪些Goal需要重置。
下面是完整的Laravel代码示例(适配你给出的代码片段):
// 先获取UTC时间(因为你的重置时间是UTC时区的) $now = \Carbon\Carbon::now('UTC'); $today = \Carbon\Carbon::today('UTC'); // 查询需要重置的Goal数据 $goals = \App\Goal::query() // 筛选「当日未重置」的Goal:要么从未重置过,要么最后重置时间早于今天 ->where(function ($query) use ($today) { $query->whereNull('last_reset_at') ->orWhereDate('last_reset_at', '<', $today); }) // 筛选「当前时间已过用户设置的重置时间」的Goal(只比较时间部分) ->whereTime('reset_time', '<=', $now->toTimeString()) ->get(); // 执行重置操作 foreach ($goals as $goal) { $goal->update([ 'progress' => 0, // 把进度清零,根据你的需求调整 'last_reset_at' => $now // 标记为已重置 ]); }
关键逻辑解释:
- 时区统一:全程用UTC时间处理,避免服务器时区和用户设置的UTC重置时间出现偏差。
- 当日未重置判断:用嵌套的
where子句覆盖两种情况:新创建的Goal还没重置过(last_reset_at为null),或者上次重置是在昨天及更早的日期。 - 重置时间判断:
whereTime只比较时间部分(比如用户设的是04:00:00,现在UTC时间是04:01:00,就满足条件),不管日期,这样每天到点都会触发。
额外注意事项:
- 如果你的
reset_time字段存的是完整的datetime而非单独的时间字符串,那需要用数据库函数提取时间部分来比较,比如MySQL可以这么写:->whereRaw('TIME(reset_time) <= ?', [$now->toTimeString()]) - 调度任务要指定UTC时区,比如在Laravel的
App\Console\Kernel.php中:protected function schedule(Schedule $schedule) { $schedule->command('goals:reset')->everyMinute()->timezone('UTC'); } - 给
last_reset_at和reset_time加数据库索引,能提升每分钟查询的效率,避免数据量大时变慢。
内容的提问来源于stack exchange,提问作者Ross
相关产品推荐
相关产品推荐

