Date arithmetic used across GanttEx.
GanttEx works with NaiveDateTime values internally, the same way the
original DHTMLX Gantt works with local Date objects: a Gantt chart shows
wall-clock time, so time zones are left to the host application.
Durations are always expressed as an integer amount of a unit:
:minute,:hour,:dayand:weekhave a fixed length:month,:quarterand:yearfollow the calendar (a month can have 28 to 31 days)
Examples
iex> GanttEx.Dates.add(~N[2025-01-30 00:00:00], 1, :month)
~N[2025-02-28 00:00:00]
iex> GanttEx.Dates.diff(~N[2025-01-01 00:00:00], ~N[2025-01-04 00:00:00], :day)
3
iex> GanttEx.Dates.floor(~N[2025-05-14 13:45:00], :week)
~N[2025-05-12 00:00:00]
Summary
Functions
Adds amount units to datetime. Negative amounts move backwards.
Casts a date-like value into a NaiveDateTime truncated to seconds.
Like cast/1 but raises ArgumentError on invalid input.
Casts a unit given as atom or string.
Rounds datetime up to the start of the next unit, unless it is already
aligned.
Returns the duration between from and to in unit, rounded to the
nearest integer. The result is negative when to is before from.
Like diff/3 but returns the exact (fractional) amount.
Rounds datetime down to the start of unit.
Converts gregorian seconds back into a NaiveDateTime.
Returns the ISO 8601 week number of datetime.
Returns the latest of two datetimes (ignoring nil).
Returns the earliest of two datetimes (ignoring nil).
Rounds datetime to the nearest boundary of unit.
Converts a NaiveDateTime into gregorian seconds (useful for fast math).
Returns true if unit is a supported duration unit.
Returns the length in seconds of a fixed-length unit.
Returns all supported units, from the smallest to the largest.
Types
Functions
@spec add(NaiveDateTime.t(), number(), unit()) :: NaiveDateTime.t()
Adds amount units to datetime. Negative amounts move backwards.
Calendar units clamp the day when the target month is shorter.
Examples
iex> GanttEx.Dates.add(~N[2025-01-01 00:00:00], 36, :hour)
~N[2025-01-02 12:00:00]
iex> GanttEx.Dates.add(~N[2025-01-31 00:00:00], 1, :quarter)
~N[2025-04-30 00:00:00]
iex> GanttEx.Dates.add(~N[2025-01-10 00:00:00], -1, :week)
~N[2025-01-03 00:00:00]
@spec cast(term()) :: {:ok, NaiveDateTime.t() | nil} | :error
Casts a date-like value into a NaiveDateTime truncated to seconds.
Accepts NaiveDateTime, DateTime (converted to its wall-clock time),
Date (midnight), ISO 8601 strings ("2025-01-31", "2025-01-31 10:30",
"2025-01-31T10:30:00") and the DHTMLX default format ("31-01-2025",
"31-01-2025 10:30"). nil is returned as {:ok, nil}.
Examples
iex> GanttEx.Dates.cast(~D[2025-03-01])
{:ok, ~N[2025-03-01 00:00:00]}
iex> GanttEx.Dates.cast("2025-03-01 08:30")
{:ok, ~N[2025-03-01 08:30:00]}
iex> GanttEx.Dates.cast("01-03-2025")
{:ok, ~N[2025-03-01 00:00:00]}
iex> GanttEx.Dates.cast(nil)
{:ok, nil}
iex> GanttEx.Dates.cast("yesterday")
:error
@spec cast!(term()) :: NaiveDateTime.t() | nil
Like cast/1 but raises ArgumentError on invalid input.
iex> GanttEx.Dates.cast!("2025-01-01")
~N[2025-01-01 00:00:00]
Casts a unit given as atom or string.
iex> GanttEx.Dates.cast_unit("hour")
{:ok, :hour}
iex> GanttEx.Dates.cast_unit(:day)
{:ok, :day}
iex> GanttEx.Dates.cast_unit("decade")
:error
@spec ceil(NaiveDateTime.t(), unit(), keyword()) :: NaiveDateTime.t()
Rounds datetime up to the start of the next unit, unless it is already
aligned.
Examples
iex> GanttEx.Dates.ceil(~N[2025-05-14 13:45:10], :day)
~N[2025-05-15 00:00:00]
iex> GanttEx.Dates.ceil(~N[2025-05-01 00:00:00], :month)
~N[2025-05-01 00:00:00]
@spec diff(NaiveDateTime.t(), NaiveDateTime.t(), unit()) :: integer()
Returns the duration between from and to in unit, rounded to the
nearest integer. The result is negative when to is before from.
Examples
iex> GanttEx.Dates.diff(~N[2025-01-01 00:00:00], ~N[2025-01-01 18:00:00], :day)
1
iex> GanttEx.Dates.diff(~N[2025-01-15 00:00:00], ~N[2025-03-15 00:00:00], :month)
2
iex> GanttEx.Dates.diff(~N[2025-01-01 00:00:00], ~N[2024-12-31 00:00:00], :hour)
-24
@spec diff_float(NaiveDateTime.t(), NaiveDateTime.t(), unit()) :: float()
Like diff/3 but returns the exact (fractional) amount.
iex> GanttEx.Dates.diff_float(~N[2025-01-01 00:00:00], ~N[2025-01-01 12:00:00], :day)
0.5
@spec floor(NaiveDateTime.t(), unit(), keyword()) :: NaiveDateTime.t()
Rounds datetime down to the start of unit.
Weeks start on Monday by default; pass week_start: 7 to start on Sunday
(ISO day numbers, 1 = Monday ... 7 = Sunday).
Examples
iex> GanttEx.Dates.floor(~N[2025-05-14 13:45:10], :hour)
~N[2025-05-14 13:00:00]
iex> GanttEx.Dates.floor(~N[2025-05-14 13:45:10], :quarter)
~N[2025-04-01 00:00:00]
iex> GanttEx.Dates.floor(~N[2025-05-14 13:45:10], :week, week_start: 7)
~N[2025-05-11 00:00:00]
@spec from_seconds(number()) :: NaiveDateTime.t()
Converts gregorian seconds back into a NaiveDateTime.
iex> GanttEx.Dates.from_seconds(60)
~N[0000-01-01 00:01:00]
@spec iso_week(NaiveDateTime.t() | Date.t()) :: 1..53
Returns the ISO 8601 week number of datetime.
iex> GanttEx.Dates.iso_week(~N[2025-01-01 00:00:00])
1
iex> GanttEx.Dates.iso_week(~N[2024-12-30 00:00:00])
1
@spec max(NaiveDateTime.t() | nil, NaiveDateTime.t() | nil) :: NaiveDateTime.t() | nil
Returns the latest of two datetimes (ignoring nil).
iex> GanttEx.Dates.max(~N[2025-01-02 00:00:00], ~N[2025-01-01 00:00:00])
~N[2025-01-02 00:00:00]
@spec min(NaiveDateTime.t() | nil, NaiveDateTime.t() | nil) :: NaiveDateTime.t() | nil
Returns the earliest of two datetimes (ignoring nil).
iex> GanttEx.Dates.min(~N[2025-01-02 00:00:00], ~N[2025-01-01 00:00:00])
~N[2025-01-01 00:00:00]
iex> GanttEx.Dates.min(nil, ~N[2025-01-01 00:00:00])
~N[2025-01-01 00:00:00]
@spec round(NaiveDateTime.t(), unit(), keyword()) :: NaiveDateTime.t()
Rounds datetime to the nearest boundary of unit.
iex> GanttEx.Dates.round(~N[2025-05-14 13:00:00], :day)
~N[2025-05-15 00:00:00]
iex> GanttEx.Dates.round(~N[2025-05-14 11:59:00], :day)
~N[2025-05-14 00:00:00]
@spec to_seconds(NaiveDateTime.t()) :: integer()
Converts a NaiveDateTime into gregorian seconds (useful for fast math).
iex> GanttEx.Dates.to_seconds(~N[0000-01-01 00:01:00])
60
Returns true if unit is a supported duration unit.
iex> GanttEx.Dates.unit?(:day)
true
iex> GanttEx.Dates.unit?(:fortnight)
false
@spec unit_seconds(unit()) :: pos_integer() | nil
Returns the length in seconds of a fixed-length unit.
iex> GanttEx.Dates.unit_seconds(:hour)
3600
iex> GanttEx.Dates.unit_seconds(:month)
nil
@spec units() :: [unit()]
Returns all supported units, from the smallest to the largest.
iex> GanttEx.Dates.units()
[:minute, :hour, :day, :week, :month, :quarter, :year]