bitwalker / bitwalker/timex

The typespecs of `Timex.Format.DateTime.Formatters.Relative` do not correspond with supported types

Open
#774 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Elixir
Stars
1.8k
Forks
407
PR merge metrics
No merged PRs in 30d

Description

### Steps to reproduce

```
iex(1)> Timex.Format.DateTime.Formatters.Relative.format(~T[12:00:00], "{relative}")
** (ArithmeticError) bad argument in arithmetic expression: div({:error, :invalid_date}, 31104000)
:erlang.div({:error, :invalid_date}, 31104000)
(timex 3.7.11) lib/format/datetime/formatters/relative.ex:227: Timex.Format.DateTime.Formatters.Relative.do_format/5
iex:1: (file)

iex(1)> Timex.format(~T[12:00:00], "{relative}", :relative)
** (ArithmeticError) bad argument in arithmetic expression: div({:error, :invalid_date}, 31104000)
:erlang.div({:error, :invalid_date}, 31104000)
(timex 3.7.11) lib/format/datetime/formatters/relative.ex:227: Timex.Format.DateTime.Formatters.Relative.do_format/5
iex:1: (file)

iex(1)> Timex.Format.DateTime.Formatters.Relative.lformat(~T[12:00:00], "{relative}", "en")
** (ArithmeticError) bad argument in arithmetic expression: div({:error, :invalid_date}, 31104000)
:erlang.div({:error, :invalid_date}, 31104000)
(timex 3.7.11) lib/format/datetime/formatters/relative.ex:227: Timex.Format.DateTime.Formatters.Relative.do_format/5
iex:1: (file)

iex(1)> Timex.lformat(~T[12:00:00], "{relative}", "en", :relative)
** (ArithmeticError) bad argument in arithmetic expression: div({:error, :invalid_date}, 31104000)
:erlang.div({:error, :invalid_date}, 31104000)
(timex 3.7.11) lib/format/datetime/formatters/relative.ex:227: Timex.Format.DateTime.Formatters.Relative.do_format/5
iex:1: (file)
```

### Description of issue

`Timex.Types.calendar_types()` and `Timex.Types.valid_datetime()` include `Time.t()` since 2a912f3b3d034560431545c5386a6ef4668b945c.
However no support for `Time.t()` was ever added to align with the updated typespec changes. The docs in e.g. `Timex.Format.DateTime.Formatter` correctly state that the datetime formatter only supports `DateTime.t()`, `Date.t()` and `NaiveDateTime.t()`. This means that typespecs of the following functions don't correspond to what they actually support:
- `Timex.Format.DateTime.Formatters.Relative.format/2`
- `Timex.Format.DateTime.Formatters.Relative.format!/2`
- `Timex.Format.DateTime.Formatters.Relative.lformat/3`
- `Timex.Format.DateTime.Formatters.Relative.lformat!/3`

The errors seen above in `Steps to reproduce` are caused by a call to `Timex.Protocol.to_naive_datetime/1` (which is referenced by both `Timex.Format.DateTime.Formatters.Relative.lformat/3` and `Timex.Format.DateTime.Formatters.Relative.relative_to/4`) because the protocol is not implemented for `Time`.

### Ways to solve

Option 1:
- Remove `Time.t()` from the typespecs
- Remove `Time` from the guard in `Timex.Format.DateTime.Formatter.lformat/3` such that the function call instead returns `{:error, :invalid_date}` when a `Time`-struct is passed

Option 2:
- Add support for `Time.t()`
I would expect such support to act like the behaviour of a passed 'today'-value of type `DateTime` or `NaiveDateTime`, i.e. returning values such as `{:ok, "8 hours ago"}` or `{:ok, "in 1 hour"}`.
I'm not sure if it makes sense to implement `Timex.Protocol` for `Time` since a lot of the functions are date-related, so maybe it makes sense to instead make a separate clause of `Timex.Format.DateTime.Formatters.Relative.lformat/3` which handles `Time` just slightly differently to how `Date`, `DateTime` and `NaiveDateTime` are handled.
(Very similar function clause, but call `do_format/5` with the passed `Time`-struct and `Time.utc_now()` instead of `Timex.Protocol.to_naive_datetime(date)` and `Timex.Protocol.now()`?)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.