寻找下一个生日来庆祝

Find next birthdays to celebrate

我的 phoenixframework 项目中有一个用户模型,其生日属性包含 Timex.Ecto.Date 值。

defmodule MyProject.User do
  use MyProject.Web, :model

  schema "users" do
    field :active, :boolean
    field :birthday, Timex.Ecto.Date
    field :login, :string
    field :email, :string
    field :password, :string, virtual: true
    field :password_hash, :string
    field :name, :string
    field :nickname, :string

    timestamps
  end

  # ... changeset and other code ...
end

现在我尝试查找所有将在从现在起的未来 30 天内庆祝生日的用户。假设有一个出生日期为 1980-02-01 的用户记录。今天是 2017-01-13。

我现在拥有的:

{:ok, date_from} =
  Timex.local
  |> Timex.Ecto.Date.cast

{:ok, date_to} =
  Timex.local
  |> Timex.add(Timex.Duration.from_days(30))
  |> Timex.Ecto.Date.cast

MyProject.Repo(from(u in MyProject.User, where: u.birthday >= ^date_from, where: u.birthday <= ^date_to))

因为年份不能用。我必须如何构建 ecto 查询?

我不知道用 Ecto 明确执行此操作的任何可能性,但以下原始 SQL 应该适用于 MySQL(仅 WHERE 子句):

WHERE DAY(bd) > DAY(NOW()) AND MONTH(db) = MONTH(NOW()) 
   OR DAY(bd) <= DAY(NOW()) AND MONTH(db) = MOD(MONTH(NOW()), 12) + 1 

对于 PostgreSQL 将 DAY(XXX) 更改为 EXTRACT(DAY FROM XXX):

WHERE EXTRACT(DAY FROM bd) > EXTRACT(DAY FROM NOW()) ....

这些子句可以按原样用于 Ecto 个片段。

在 PostgreSQL 中,我会使用 age 来获取出生日期和现在之间的间隔,将其截断为年份,将其添加到出生日期以获得下一个生日,然后查看如果在接下来的 30 天内:

postgres=# select current_date;
    date
------------
 2017-01-14
(1 row)

postgres=# select '2000-01-20'::date + date_trunc('year', age('2000-01-20'::date)) + interval '1 year' <= current_date + interval '30 days';
 ?column?
----------
 t
(1 row)

postgres=# select '2000-02-20'::date + date_trunc('year', age('2000-02-20'::date)) + interval '1 year' <= current_date + interval '30 days';
 ?column?
----------
 f
(1 row)

对于 Ecto,这应该看起来像(未经测试):

from(u in User, where: fragment("? + date_trunc('year', age(?)) + interval '1 year' <= current_date + interval '30 days'", u.birthday, u.birthday))

现在将间隔更改为 '1 month' 也很简单,PostgreSQL 将正确地添加当月的天数,并为您提供生日在 1 个月内而不是 30 天内的用户。