如何从当前日期和 Ecto.Date 实例中获取年份差异
How to get difference in years from current date and Ecto.Date instance
假设我有一个 Person
模型,每个人都有一个生日字段设置为 Ecto.Date
列。
因此,如果我从数据库中检索代表此模型实例的记录,从他的 birthday
列获取此人年龄的最佳方法是什么?
不确定 'best way',但这是 a 方式:
defmodule AgeCalc do
@spec age(Ecto.Date.t, atom|{integer, integer, integer}) :: integer
def age(%Ecto.Date{day: d, month: m, year: y}, as_of \ :now) do
do_age({y, m, d}, as_of)
end
###########
# Internals
###########
@doc false
def do_age(birthday, :now) do
{today, _time} = :calendar.now_to_datetime(:erlang.now)
calc_diff(birthday, today)
end
def do_age(birthday, date), do: calc_diff(birthday, date)
@doc false
def calc_diff({y1, m1, d1}, {y2, m2, d2}) when m2 > m1 or (m2 == m1 and d2 >= d1) do
y2 - y1
end
def calc_diff({y1,_,_}, {y2,_,_}), do: (y2 - y1) - 1
end
用法是这样的:(今天是2015年9月27日)
iex(1)> AgeCalc.age(%Ecto.Date{day: 27, month: 9, year: 2000})
15
iex(2)> AgeCalc.age(%Ecto.Date{day: 28, month: 9, year: 2000})
14
或者,对于除今天之外的其他内容的手动计算:
iex(3)> AgeCalc.age(%Ecto.Date{day: 28, month: 9, year: 2000}, {2034, 12, 25})
34
我使用 Ecto 的查询 API 中的 fragment
。我有一个用户 table 有一个生日列,我正在使用以下查询:
Repo.all(from u in User, select: fragment("age(?)", u.birthday))
查询 returns 一个 %Postgrex.Interval{}
,字段为 days
、months
和 secs
。用几个月 div
乘以 12 得到年龄。
我喜欢 Timex,但使用 Postgres 的原生 age
函数对我来说似乎更干净、更快捷。
我在长生不老药里是这样做的
def calculate_age(dob) when is_binary(dob)
def calculate_age(dob) when is_binary(dob) do
today = Date.utc_today()
dob = Date.from_iso8601! dob
today.year - dob.year
end
我知道这有点旧,但我只是 运行 并编写了我自己的函数,我认为它更容易理解,使用 Date
from Elixir which has since replaced Ecto.Date
:
def get_person_age(%Person{} = person) do
today = Date.utc_today()
{:ok, today_in_birthday_year} = Date.new(person.birthday.year, today.month, today.day)
years_diff = today.year - person.birthday.year
if Date.compare(today_in_birthday_year, person.birthday) == :lt do
years_diff - 1
else
years_diff
end
end
假设我有一个 Person
模型,每个人都有一个生日字段设置为 Ecto.Date
列。
因此,如果我从数据库中检索代表此模型实例的记录,从他的 birthday
列获取此人年龄的最佳方法是什么?
不确定 'best way',但这是 a 方式:
defmodule AgeCalc do
@spec age(Ecto.Date.t, atom|{integer, integer, integer}) :: integer
def age(%Ecto.Date{day: d, month: m, year: y}, as_of \ :now) do
do_age({y, m, d}, as_of)
end
###########
# Internals
###########
@doc false
def do_age(birthday, :now) do
{today, _time} = :calendar.now_to_datetime(:erlang.now)
calc_diff(birthday, today)
end
def do_age(birthday, date), do: calc_diff(birthday, date)
@doc false
def calc_diff({y1, m1, d1}, {y2, m2, d2}) when m2 > m1 or (m2 == m1 and d2 >= d1) do
y2 - y1
end
def calc_diff({y1,_,_}, {y2,_,_}), do: (y2 - y1) - 1
end
用法是这样的:(今天是2015年9月27日)
iex(1)> AgeCalc.age(%Ecto.Date{day: 27, month: 9, year: 2000})
15
iex(2)> AgeCalc.age(%Ecto.Date{day: 28, month: 9, year: 2000})
14
或者,对于除今天之外的其他内容的手动计算:
iex(3)> AgeCalc.age(%Ecto.Date{day: 28, month: 9, year: 2000}, {2034, 12, 25})
34
我使用 Ecto 的查询 API 中的 fragment
。我有一个用户 table 有一个生日列,我正在使用以下查询:
Repo.all(from u in User, select: fragment("age(?)", u.birthday))
查询 returns 一个 %Postgrex.Interval{}
,字段为 days
、months
和 secs
。用几个月 div
乘以 12 得到年龄。
我喜欢 Timex,但使用 Postgres 的原生 age
函数对我来说似乎更干净、更快捷。
我在长生不老药里是这样做的
def calculate_age(dob) when is_binary(dob)
def calculate_age(dob) when is_binary(dob) do
today = Date.utc_today()
dob = Date.from_iso8601! dob
today.year - dob.year
end
我知道这有点旧,但我只是 运行 并编写了我自己的函数,我认为它更容易理解,使用 Date
from Elixir which has since replaced Ecto.Date
:
def get_person_age(%Person{} = person) do
today = Date.utc_today()
{:ok, today_in_birthday_year} = Date.new(person.birthday.year, today.month, today.day)
years_diff = today.year - person.birthday.year
if Date.compare(today_in_birthday_year, person.birthday) == :lt do
years_diff - 1
else
years_diff
end
end