【问题标题】:How to get difference in years from current date and Ecto.Date instance如何从当前日期和 Ecto.Date 实例中获取年份差异
【发布时间】:2022-02-09 10:43:49
【问题描述】:

假设我有一个Person 模型,每个人都有一个生日字段设置为Ecto.Date 列。

如果我从数据库中检索代表该模型实例的记录,那么从他的birthday 列中获取此人年龄的最佳方法是什么?

【问题讨论】:

    标签: elixir phoenix-framework ecto


    【解决方案1】:

    不确定“最佳方式”,但这是一种方式:

    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
    

    【讨论】:

    • 有几个用于通用日期/时间计算的库。 Timex 是我熟悉的一种。 github.com/bitwalker/timex
    • 我经常使用 vanilla Timex - 查看我找到的文档 :timex_ecto,这似乎是一个不错的选择,虽然我自己没有使用它,它可能需要大量的重新 -基于示例的工具。
    【解决方案2】:

    我使用 Ecto 查询 API 中的 fragment。我有一个带有生日列的用户表,并且正在使用以下查询:

    Repo.all(from u in User, select: fragment("age(?)", u.birthday))
    

    查询返回一个%Postgrex.Interval{},其中包含daysmonthssecs 字段。用几个月的时间和div 到 12 岁才能得到年龄。

    我喜欢 Timex,但使用 Postgres 的原生 age 函数对我来说似乎更干净、更快捷。

    【讨论】:

    • 它可能会更快,但是您只为 postgres 引入了特定的 SQL,如果您决定迁移到另一个引擎,您的代码将不再工作。
    【解决方案3】:

    我是这样在灵药中做到的

      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
    

    【讨论】:

    • 今年还没有生日的时候会返回错误的年龄。
    【解决方案4】:

    我知道这有点旧,但我只是遇到了这个并编写了我自己的函数,我认为它更容易理解,使用来自 Elixir 的 Date 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-12
      • 2020-03-15
      • 2021-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多