提问者:小点点

获取在其时区今天生日的用户


我们有来自多个时区的用户,我们的命令运行,看看我们是否有一个用户的生日是今天在他们的时区。

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'列,为我们获取生日是今天的用户。


共1个答案

匿名用户

我脑子里的逻辑是

假设我想获得在给定的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();

未测试