# `Calendrical.Shift`

Date arithmetic for a calendar whose months are counted by their
position in the year: the implementation of `c:Calendrical.shift/6`
and `c:Calendrical.diff/3` that `use Calendrical.Calendar` supplies,
computed from the calendar's kernel.

The contract every calendar's `shift/6` honours, whatever its maker:

* Days and weeks are counted on the day line, through
  `c:Calendrical.date_to_iso_days/3`.

* Months are counted by position: the next month is the next position
  in the year, or the first of the year after. A quarter is three
  months.

* Years keep the month as the calendar's culture names it, its
  traditional number (`Calendrical.Month.traditional_month/3`), so
  Nisan stays Nisan whatever its position, and a leap month the
  resulting year lacks becomes the month it repeats.

* A count that reaches or crosses a year 0 the calendar does not have
  (`info().year_zero?`) goes one year further the way it was going.

* With `clamp: true`, the default, a day the resulting month lacks
  becomes the month's last day. With `clamp: false` the fields are
  returned as counted, and may not be a date of the calendar.

# `calendar`

```elixir
@type calendar() :: module()
```

A calendar module.

# `unit`

```elixir
@type unit() :: :years | :quarters | :months | :weeks | :days
```

A unit of the shift.

# `diff`

```elixir
@spec diff(
  calendar(),
  {Calendar.year(), Calendar.month(), Calendar.day()},
  {Calendar.year(), Calendar.month(), Calendar.day()},
  unit()
) :: integer()
```

Returns the whole number of units from one date of the calendar to
another, as `shift/7` adds them.

The count is the largest number of units that `shift/7` can add to the
earlier date without passing the later one, and is negative when `to`
is before `from`.

### Arguments

* `calendar` is a calendar module.

* `from` and `to` are dates of the calendar as `{year, month, day}`.

* `unit` is one of `:years`, `:quarters`, `:months`, `:weeks` or
  `:days`.

### Returns

* An integer.

### Examples

    iex> Calendrical.Shift.diff(Calendrical.Gregorian, {2026, 1, 31}, {2026, 2, 28}, :months)
    1

    iex> Calendrical.Shift.diff(Calendrical.Hebrew, {5784, 6, 30}, {5785, 6, 29}, :months)
    13

# `shift`

```elixir
@spec shift(
  calendar(),
  Calendar.year(),
  Calendar.month(),
  Calendar.day(),
  unit(),
  integer(),
  keyword()
) ::
  {Calendar.year(), Calendar.month(), Calendar.day()}
```

Returns the date a number of units on from a date of the calendar.

### Arguments

* `calendar` is a calendar module.

* `year`, `month` and `day` are the fields of a date of the calendar.

* `unit` is one of `:years`, `:quarters`, `:months`, `:weeks` or
  `:days`.

* `count` is the number of units, which may be negative.

* `options` is a keyword list of options.

### Options

* `:clamp` is whether a day the resulting month lacks becomes its last
  day. The default is `true`.

### Returns

* `{year, month, day}` of the calendar.

### Examples

    iex> Calendrical.Shift.shift(Calendrical.Gregorian, 2026, 1, 31, :months, 1, [])
    {2026, 2, 28}

    iex> Calendrical.Shift.shift(Calendrical.Gregorian, 2026, 1, 31, :months, 1, clamp: false)
    {2026, 2, 31}

    # Adar I of the leap year 5784 becomes Adar in 5785, which has 29 days
    iex> Calendrical.Shift.shift(Calendrical.Hebrew, 5784, 6, 30, :years, 1, [])
    {5785, 6, 29}

    # 15 Nisan, the 8th month of the leap year 5784 and the 7th of 5785
    iex> Calendrical.Shift.shift(Calendrical.Hebrew, 5784, 8, 15, :years, 1, [])
    {5785, 7, 15}

    # The Julian calendar has no year 0
    iex> Calendrical.Shift.shift(Calendrical.Julian, -1, 6, 15, :years, 1, [])
    {1, 6, 15}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
