Skip to content

Commit 1327c0c

Browse files
committed
Improve docs for shift vs add
1 parent 64c61df commit 1327c0c

File tree

4 files changed

+61
-30
lines changed

4 files changed

+61
-30
lines changed

lib/elixir/lib/calendar/date.ex

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -691,10 +691,15 @@ defmodule Date do
691691
@doc """
692692
Adds the number of days to the given `date`.
693693
694-
The days are counted as Gregorian days. The date is returned in the same
695-
calendar as it was given in.
696-
697-
To shift a date by a `Duration` and according to its underlying calendar, use `Date.shift/2`.
694+
> #### Prefer `shift/2` {: .info}
695+
>
696+
> Prefer `shift/2` over `add/2`, as it offers a more ergonomic API.
697+
>
698+
> `add/2` always considers a day to be measured according to the
699+
> `Calendar.ISO`.
700+
701+
The days are counted as Gregorian days, independent of the underlying
702+
calendar. The date is returned in the same calendar as it was given in.
698703
699704
## Examples
700705

lib/elixir/lib/calendar/datetime.ex

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,30 +1611,42 @@ defmodule DateTime do
16111611
@doc """
16121612
Adds a specified amount of time to a `DateTime`.
16131613
1614+
> #### Prefer `shift/2` {: .info}
1615+
>
1616+
> Prefer `shift/2` over `add/3`, as it offers a more ergonomic API.
1617+
>
1618+
> `add/3` provides a lower-level API which only supports fixed units
1619+
> such as `:hour` and `:second`, but not `:month` (as the exact length
1620+
> of a month depends on the current month). `add/3` always considers
1621+
> the unit to be computed according to the `Calendar.ISO`.
1622+
16141623
Accepts an `amount_to_add` in any `unit`. `unit` can be `:day`,
16151624
`:hour`, `:minute`, `:second` or any subsecond precision from
16161625
`t:System.time_unit/0`. It defaults to `:second`. Negative values
16171626
will move backwards in time.
16181627
1619-
This function always considers the unit to be computed according
1620-
to the `Calendar.ISO`.
1621-
16221628
This function relies on a contiguous representation of time,
1623-
ignoring the wall time and timezone changes. For example, if you add
1624-
one day when there are summer time/daylight saving time changes,
1625-
it will also change the time forward or backward by one hour,
1626-
so the elapsed time is precisely 24 hours. Similarly, adding just
1627-
a few seconds to a datetime just before "spring forward" can cause
1628-
wall time to increase by more than an hour.
1629+
ignoring timezone changes. For example, if you add one day when there
1630+
are summer time/daylight saving time changes, it will also change the
1631+
time forward or backward by one hour, so the elapsed time is precisely
1632+
24 hours. Similarly, adding just a few seconds to a datetime just before
1633+
"spring forward" can cause wall time to increase by more than an hour.
16291634
16301635
While this means this function is precise in terms of elapsed time,
1631-
its result may be misleading in certain use cases. For example, if a
1636+
its result may be confusing in certain use cases. For example, if a
16321637
user requests a meeting to happen every day at 15:00 and you use this
16331638
function to compute all future meetings by adding day after day, this
16341639
function may change the meeting time to 14:00 or 16:00 if there are
1635-
changes to the current timezone. Computing of recurring datetimes is
1636-
not currently supported in Elixir's standard library but it is available
1637-
by third-party libraries.
1640+
changes to the current timezone.
1641+
1642+
In case you don't want these changes to happen automatically or you
1643+
want to surface time zone conflicts to the user, you can add to
1644+
the datetime as a naive datetime and then use `from_naive/2`:
1645+
1646+
dt |> NaiveDateTime.add(1, :day) |> DateTime.from_naive(dt.time_zone)
1647+
1648+
The above will surface time jumps and ambiguous datetimes, allowing you
1649+
to deal with them accordingly.
16381650
16391651
## Examples
16401652
@@ -1664,8 +1676,6 @@ defmodule DateTime do
16641676
iex> result.microsecond
16651677
{21000, 3}
16661678
1667-
To shift a datetime by a `Duration` and according to its underlying calendar, use `DateTime.shift/3`.
1668-
16691679
"""
16701680
@doc since: "1.8.0"
16711681
@spec add(
@@ -1739,7 +1749,7 @@ defmodule DateTime do
17391749
to UTC, and finally computing the new timezone in case of shifts.
17401750
This ensures `shift/3` always returns a valid datetime.
17411751
1742-
On the other hand, time zones that observe "Daylight Saving Time"
1752+
Consequently, time zones that observe "Daylight Saving Time"
17431753
or other changes, across summer/winter time will add/remove hours
17441754
from the resulting datetime:
17451755
@@ -1751,12 +1761,22 @@ defmodule DateTime do
17511761
DateTime.shift(dt, hour: 2)
17521762
#=> #DateTime<2018-11-04 01:00:00-08:00 PST America/Los_Angeles>
17531763
1764+
Although the first example shows a difference of 2 hours when
1765+
comparing the wall clocks of the given datetime with the returned one,
1766+
due to the "spring forward" time jump, the actual ellapsed time is
1767+
still exactly of 1 hour.
1768+
17541769
In case you don't want these changes to happen automatically or you
17551770
want to surface time zone conflicts to the user, you can shift
17561771
the datetime as a naive datetime and then use `from_naive/2`:
17571772
17581773
dt |> NaiveDateTime.shift(duration) |> DateTime.from_naive(dt.time_zone)
17591774
1775+
The above will surface time jumps and ambiguous datetimes, allowing you
1776+
to deal with them accordingly.
1777+
1778+
## ISO calendar considerations
1779+
17601780
When using the default ISO calendar, durations are collapsed and
17611781
applied in the order of months, then seconds and microseconds:
17621782

lib/elixir/lib/calendar/naive_datetime.ex

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -391,14 +391,20 @@ defmodule NaiveDateTime do
391391
@doc """
392392
Adds a specified amount of time to a `NaiveDateTime`.
393393
394+
> #### Prefer `shift/2` {: .info}
395+
>
396+
> Prefer `shift/2` over `add/3`, as it offers a more ergonomic API.
397+
>
398+
> `add/3` provides a lower-level API which only supports fixed units
399+
> such as `:hour` and `:second`, but not `:month` (as the exact length
400+
> of a month depends on the current month). `add/3` always considers
401+
> the unit to be computed according to the `Calendar.ISO`.
402+
394403
Accepts an `amount_to_add` in any `unit`. `unit` can be `:day`,
395404
`:hour`, `:minute`, `:second` or any subsecond precision from
396405
`t:System.time_unit/0`. It defaults to `:second`. Negative values
397406
will move backwards in time.
398407
399-
This function always consider the unit to be computed according
400-
to the `Calendar.ISO`.
401-
402408
## Examples
403409
404410
It uses seconds by default:
@@ -447,8 +453,6 @@ defmodule NaiveDateTime do
447453
iex> NaiveDateTime.add(dt, 21, :second)
448454
~N[2000-02-29 23:00:28]
449455
450-
To shift a naive datetime by a `Duration` and according to its underlying calendar, use `NaiveDateTime.shift/2`.
451-
452456
"""
453457
@doc since: "1.4.0"
454458
@spec add(Calendar.naive_datetime(), integer, :day | :hour | :minute | System.time_unit()) :: t

lib/elixir/lib/calendar/time.ex

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -505,14 +505,18 @@ defmodule Time do
505505
@doc """
506506
Adds the `amount_to_add` of `unit`s to the given `time`.
507507
508+
> #### Prefer `shift/2` {: .info}
509+
>
510+
> Prefer `shift/2` over `add/3`, as it offers a more ergonomic API.
511+
>
512+
> `add/3` always considers the unit to be computed according to
513+
> the `Calendar.ISO`.
514+
508515
Accepts an `amount_to_add` in any `unit`. `unit` can be
509516
`:hour`, `:minute`, `:second` or any subsecond precision from
510517
`t:System.time_unit/0`. It defaults to `:second`. Negative values
511518
will move backwards in time.
512519
513-
This function always consider the unit to be computed according
514-
to the `Calendar.ISO`.
515-
516520
Note the result value represents the time of day, meaning that it is cyclic,
517521
for instance, it will never go over 24 hours for the ISO calendar.
518522
@@ -549,8 +553,6 @@ defmodule Time do
549553
iex> result.microsecond
550554
{21000, 3}
551555
552-
To shift a time by a `Duration` and according to its underlying calendar, use `Time.shift/2`.
553-
554556
"""
555557
@doc since: "1.6.0"
556558
@spec add(Calendar.time(), integer, :hour | :minute | System.time_unit()) :: t

0 commit comments

Comments
 (0)