*Preface*

We currently have `add/2-3` to manipulate calendar types in the standard 
library. These functions allow adding a specified amount of time of given 
unit to a date/time. The standard library currently misses means to apply 
more complex, or logical *durations *to calendar types. e.g. adding a 
month, a week, or one month and 10 days to a date.

*Reasons for it*

While similar functionality exists in libraries, such as CLDR, Timex, Tox, 
adding this functionality to the standard library has already been 
requested and discussed at multiple occasions over the past years. To list 
a few examples:

- https://github.com/elixir-lang/elixir/pull/10199
- https://elixirforum.com/t/get-date-n-months-years-in-the-past/48346/3
- 
https://elixir-lang.slack.com/archives/C0HEX82NR/p1709581478427009?thread_ts=1709368588.334759&cid=C0HEX82NR

Furthermore the shift behaviour in the extremely popular library Timex 
changed <https://github.com/bitwalker/timex/issues/731> in Elixir >= 1.14.3 
which may have complicated the mostly lean and non-breaking language 
upgrade Elixir has to offer.

Elixir has a great set of modules and functions that deal with date and 
time, the APIs are consistent and `shift/2-3` should fit right in, solving 
many standard needs of various industries, be it for reporting, 
appointments, events, finance... the list goes on, engineers probably face 
the need to shift time logically more often than not in their careers.

*Technical details*

Duration
A date or time must be shifted by a *duration*. There is an ISO8601 for 
durations <https://en.wikipedia.org/wiki/ISO_8601#Durations>, which the 
initial implementation is loosely following. The structure of a Duration 
lives in its own module with its own set of functions to create and 
manipulate durations. One example of where it diverts from the ISO 
standard, is that it implements microseconds. Microseconds in a *duration* 
are stored in the same format as in the time calendar types, meaning they 
integrate well and provide consistency.

Shift
The shift behaviour is implemented as a callback on Calendar and supported 
by all calendar types: Date, DateTime, NaiveDateTime and Time. Date, Time 
and NaiveDateTime each have their own implementation of a "shift", while 
DateTime gets converted to a NaiveDateTime before applying the shift, and 
is then rebuilt to a DateTime in its original timezone. `shift/2-3` also 
has guaranteed output types (which isn't a given in many libraries) and 
follows the consistent API which is established in the calendar modules.

Find the current state of the implementation here: 
https://github.com/elixir-lang/elixir/pull/13385

*Benchmarks*

There are some benchmarks + StreamData tests in the PR description.

*Outlook*

*After  *adding the Duration type and shift behaviour to the standard 
library, the following things could be explored and derived from the 
initial work:


   - Implementing a protocol that allows Duration to be applied to any data 
   type, not just dates and times.
   - A range-like data type that allows us to do recurring constructs on 
   any data type. For example, Duration.interval(~D[2000-01-01], month: 1), 
   when iterated, would emit {:ok, date} | {:error, start, duration, reason}
    entries
   - A sigil for easy creation of durations: ~P[3 hours and 10 minutes]
   - Making it so add/2-3 reuses the shift_* functions

*Reasons against it*

While I am convinced that adding `shift/2-3` to the standard library would 
be very beneficial, nothing really speaks against the points mentioned 
above to be implemented in a library instead. However, something as crucial 
and central as date/time manipulation should still be part of the standard 
library, negating the risk of breaking changes, inconsistent behaviour and 
outdated or too unique ergonomics which aren't widely applicable, unlike 
what should be part of the standard library.

Many thanks to @jose & @kip for the initial reviews and everyone in advance 
taking the time to read the proposal!

Looking forward to hear other peoples ideas and opinions on the subject!

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/cb0ed628-3848-4de0-aa13-c0f4761e4d99n%40googlegroups.com.

Reply via email to