我们有来自多个时区的用户,我们的命令运行,看看我们是否有一个用户的生日是今天在他们的时区。
DB结构
id => bigInt
name => string
dob => datetime
timezone => string
dob=出生日期时区=例如:美国/纽约
我们得到所有用户的生日在UTC时间的昨天,今天和明天,以覆盖所有时区,并得到有限的用户,而不是所有用户
$users = User::whereRaw("DATE_FORMAT(dob, '%m-%d') = '" . now()->format('m-d') . "'")
->orWhereRaw("DATE_FORMAT(dob,'%m-%d') = '" . now()->subDay(1)->format('m-d') . "'")
->orWhereRaw("DATE_FORMAT(dob,'%m-%d') = '" . now()->addDay(1)->format('m-d') . "'")
->selectRaw('*')
->whereNotNull('timezone')->get();
然后我们循环访问这些用户,查看用户的生日是否在他们的时区的今天,在某个特定的时间,比如9:00AM,然后我们向他们发送问候。
foreach ($users as $user) {
if ($user->isMorningForUserOnBirthday()) {
$user->notify(new BirthdayNotification($user));
}
}
函数isMorningForUserOnBirthday()
public function isMorningForUserOnBirthday()
{
// its birthday date and for that user its time at 9:00AM
if ((now($this->timezone)->day == $this->dob->day) && now($this->timezone)->hour == 9) {
return true;
}
return false;
}
我们正在展望的是:我们正在取得成果,所有的工作都很好,在工作很好之后的下一个阶段是让它变得很棒,
我们想要重构雄辩的查询,而不是使用函数isMorningForUserOnBirthday(),我们想要使用MySql原生的东西,它可以使用用户的'timezon'列,为我们获取生日是今天的用户。
我脑子里的逻辑是
假设我想获得在给定的UTC date_time庆祝生日的所有用户
例:给定日期为:06-04(UTC)(采用月-日格式)
并且所有的dob都保存在db中并带有各自的时区,因此现在基于dob和它们的时区,我们可以计算每个dob的UTC日期
CONVERT_TZ(dob, timezone, "+00:00")
//CONVERT_TZ (dt, from_tz, to_tz)
这表示dob
在此时区
中(因为我们将它们的dob保存在它们的时区中),然后我们表示通过传递+00:00
将其转换为UTC
现在我们可以使用当前UTC日期来过滤结果
SELECT
name,
DATE_FORMAT(CONVERT_TZ(dob, timezone, "+00:00"), "%m-%d") as dob_utc
FROM users HAVING dob = "07-01";
我们需要date_formater
,因为在检查dob
时,year
并不重要。
当我们把它放进拉拉维尔的时候
$utc = now()->format('m-d')
$users = User::selectRaw("DATE_FORMAT(CONVERT_TZ(dob, timezone, '+00:00'), '%m-%d') as dob_utc")
->having("dob_utc", "=", $utc)
->whereNotNull('timezone')
->get();
未测试