如何在 Elixir 中实现 Date.add(date, n, :month)

问题描述 投票:0回答:6

如果能将其包含在标准 Elixir 库中就好了,但我们没有。

Date.add(date, n, :month) # where n could be +/-

您将如何实施这个?

这看起来是一个很好的起点:https://stackoverflow.com/a/53407676/44080

date elixir
6个回答
4
投票
Date.utc_today() |> Timex.shift(months: -1) 

3
投票

您可以使用 Timex 实现

  defp shift_by(%NaiveDateTime{:year => year, :month => month} = datetime, value, :months) do
    m = month + value
    shifted =
      cond do
        m > 0 ->
          years = div(m - 1, 12)
          month = rem(m - 1, 12) + 1
          %{datetime | :year => year + years, :month => month}
        m <= 0 ->
          years = div(m, 12) - 1
          month = 12 + rem(m, 12)
          %{datetime | :year => year + years, :month => month}
      end

    # If the shift fails, it's because it's a high day number, and the month
    # shifted to does not have that many days. This will be handled by always
    # shifting to the last day of the month shifted to.
    case :calendar.valid_date({shifted.year,shifted.month,shifted.day}) do
      false ->
        last_day = :calendar.last_day_of_the_month(shifted.year, shifted.month)
        cond do
          shifted.day <= last_day ->
            shifted
          :else ->
            %{shifted | :day => last_day}
        end
      true ->
        shifted
    end
  end

Timex 使用 MIT 许可证,因此您应该能够将其合并到几乎任何项目中。


3
投票

ex_cldr_calendars 还可以对实现

Calendar
行为的任何日历进行基本日期数学运算,添加和减去年、季度、月、周和日。

iex> Cldr.Calendar.plus ~D[2019-03-31], :months, -1
~D[2019-02-28]

# The :coerce option determines whether to force an end
# of month date when the result of the operation is an invalid date
iex> Cldr.Calendar.plus ~D[2019-03-31], :months, -1, coerce: false
{:error, :invalid_date}

1
投票

在不添加像 Timex 这样的依赖项的情况下,以下方法可以轻松添加/减去公历月份 - 假设您只需要每个月的第一天。考虑到有多少日历谬误,直接转换到一个月中的某一天可能最好通过图书馆来实现。

defmodule DateUtils
  @doc """
  Shift a given date forward or back n months
  """
  def shift_n_months(date, n) when n < 0, do: subtract_n_months(date, -1 * n)
  def shift_n_months(date, n), do: add_n_months(date, n)

  def add_n_months(date, 0), do: Date.beginning_of_month(date)

  def add_n_months(date, n) do
    date
    |> Date.end_of_month()
    |> Date.add(1)
    |> add_n_months(n - 1)
  end

  def subtract_n_months(date, 0), do: Date.beginning_of_month(date)

  def subtract_n_months(date, n) do
    date
    |> Date.beginning_of_month()
    |> Date.add(-1)
    |> subtract_n_months(n - 1)
  end
end

0
投票

从 Elixir 1.17 开始,您可以使用 Elixir 的 Date.shift/2 函数来添加或减去持续时间

Date.shift/2 期望一个日期作为它的第一个参数,一个持续时间作为它的第二个参数。

以下是取自文档

的几个示例
iex> Date.shift(~D[2016-01-03], month: 2)
~D[2016-03-03]

Date.shift(~D[2016-01-31], year: 4, day: 1).
~D[2020-02-01]

请注意,您可以使用正整数或负整数,具体取决于您要添加还是减去日期的持续时间。


-3
投票

有灵丹妙药功能

Date.add/2
。给它任何日期,它会为您添加日期。

iex>Date.add(~D[2000-01-03], -2)
~D[2000-01-01]

如果您想创建要添加的日期,那么我建议您使用

Date.new/4

iex>{:ok, date} = Date.new(year, month, day) 
iex>date |> Date.add(n)
© www.soinside.com 2019 - 2024. All rights reserved.