defmodule DateConverter do
@moduledoc """
Convert `String` to one of the `Date`, `DateTime`, `Time` or `NaiveDateTime` types.
"""
@doc """
Convert the date `String` parameter to the `Date`/`DateTime`/`NaiveDateTime`/`Time` based on the format of the provided string.
## Examples
A simple date in the format `YYYY-MM-DD` (iso8601) will be converted to the `Date` type.
iex> DateConverter.convert("2020-10-11")
Date.new(2020, 10, 11)
iex> DateConverter.convert("2020-22-11")
{:error, :invalid_date}
String in the form of `YYYY-MM-DD hh:mm::ss` will be converted to `NaiveDateTime` struct.
iex> DateConverter.convert("2020-10-11 11:34:48")
NaiveDateTime.new(2020, 10, 11, 11, 34, 48)
iex> DateConverter.convert("2020-10-11 11:34:78")
{:error, :invalid_time}
String in the form of `YYYY-MM-DDThh:mm::ss` will be converted to `DateTime` struct.
iex> DateConverter.convert("2020-10-11T11:34:48.00Z")
DateTime.new(~D[2020-10-11], ~T[11:34:48.00])
iex> DateConverter.convert("2020-10-11T11:34:78.00Z")
{:error, :invalid_time}
String in the form of `hh:mm:ss.` will be converted to `Time` struct.
iex> DateConverter.convert("11:34:48")
Time.new(11, 34, 48)
"""
def convert(date) when is_bitstring(date) do
cond do
Regex.match?(~r/^\d{4}-\d{2}-\d{2}$/, date) ->
Date.from_iso8601(date)
Regex.match?(~r/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/, date) ->
NaiveDateTime.from_iso8601(date)
Regex.match?(~r/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.+$/, date) ->
case DateTime.from_iso8601(date) do
{:ok, pdate, _} -> {:ok, pdate}
error -> error
end
Regex.match?(~r/^\d{2}:\d{2}:\d{2}([.,][0-9]{1,6})?Z?$/, date) ->
Time.from_iso8601(date)
true ->
{:error, "#{date} is not a proper date"}
end
end
end
defmodule Dsv.Date do
use Dsv.Validator
@moduledoc """
Dsv.Date module provides functions to validate a date value based on the specified rules (:min, :max, :range).
## Possible options are:
* `:min` - check if the date is later or the same as the date specified in the `:min` option.
* `:max` - check if the date is earlier or the same as the date specified in the `:max` option.
* `:range` - check if the date is between the dates specified in the `:range` options.
"""
message({:max, "Date is later than the maximum allowed date <%= options[:max] %>"})
message({:min, "Date is earlier than the minimum allowed date <%= options[:min] %>"})
message(
{:range,
"Date must be between <%= elem(options[:range], 0) %> and <%= elem(options[:range], 1) %>"}
)
message({[:min, :max], "Date must be between <%= options[:min] %> and <%= options[:max] %>"})
@doc """
The `Dsv.Date.valid?/2` function is designed to validate a given date against a set of options provided by the user.
It checks whether the date falls within the specified range or exceeds certain boundaries defined by the min and max dates.
If the date meets all of the specified conditions, the function returns an `:true` response; otherwise, it returns `:false`.
## Parameters
* `date` - The date value to validate.
* `rules` - A keyword list of validation rules.
Each rule is a tuple containing:
* The validation type (`:min`, `:max`, `:range`).
* The corresponding value or values for the validation type.
## Return
* `:true` - If the date is later than the min date provided in options, earlier than the max date provided in options, or falls between the dates specified in the range.
* `:false` - If the date does not meet any of the specified conditions.
> #### min and max options {: .info}
>
> `:min` and `:max` are inclusive
"""
def valid?(data, [{:min, min}, {:max, max} | _]) do
case compare(min, max) do
:gt -> raise "Min date (#{min}) can't be after max date (#{max})"
_ -> valid?(data, min: min) and valid?(data, max: max)
end
end
def valid?(data, [{:max, max_date} | _]) do
case compare(data, max_date) do
:gt -> false
_ -> true
end
end
def valid?(data, [{:min, min_date} | _]) do
case compare(data, min_date) do
:lt -> false
_ -> true
end
end
def valid?(data, [{:range, {min, max}} | _]), do: valid?(data, [{:min, min}, {:max, max}])
defp compare(%Date{} = date1, %Date{} = date2), do: Date.compare(date1, date2)
defp compare(%DateTime{} = date1, %DateTime{} = date2), do: DateTime.compare(date1, date2)
defp compare(%Time{} = date1, %Time{} = date2), do: Time.compare(date1, date2)
defp compare(%NaiveDateTime{} = date1, %NaiveDateTime{} = date2),
do: NaiveDateTime.compare(date1, date2)
defp compare(date1, date2) when is_bitstring(date1) do
case DateConverter.convert(date1) do
{:ok, date} -> compare(date, date2)
_ -> {:error, "#{date1} is not a proper date"}
end
end
@doc """
The `Dsv.Date.validate/2` function is designed to validate a given date against a set of options provided by the user.
It checks whether the date falls within the specified range or exceeds certain boundaries defined by the min and max dates.
If the date meets all of the specified conditions, the function returns an `:ok` response; otherwise, it returns an appropriate error message.
## Parameters
* `date` - The date value to validate.
* `rules` - A keyword list of validation rules.
Each rule is a tuple containing:
* The validation type (`:min`, `:max`, `:range`).
* The corresponding value or values for the validation type.
## Return
* `:ok` - If the date is later than the min date provided in options, earlier than the max date provided in options, or falls between the dates specified in the range.
* `{:error, message}` - If the date does not meet any of the specified conditions, where message is an appropriate string message.
> #### min and max options {: .info}
>
> `:min` and `:max` are inclusive
Examples for different types:
* [Date](#validate/2-examples-date)
* [min](#validate/2-min)
* [max](#validate/2-max)
* [min and max](#validate/2-min-max)
* [range](#validate/2-range)
* [DateTime](#validate/2-examples-datetime)
* [min](#validate/2-min-1)
* [max](#validate/2-max-1)
* [min and max](#validate/2-min-max-1)
* [range](#validate/2-range-1)
* [Time](#validate/2-examples-time)
* [min](#validate/2-min-2)
* [max](#validate/2-max-2)
* [min and max](#validate/2-min-max-2)
* [range](#validate/2-range-2)
## Examples - date
### min
`:min` example with first parameter as a string:
iex> Dsv.Date.validate("2020-10-10", min: ~D[2020-10-09])
:ok
iex> Dsv.Date.validate("2020-10-10", min: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate("2020-10-10", min: ~D[2020-10-11])
{:error, "Date is earlier than the minimum allowed date 2020-10-11"}
`:min` example with first parameter as a date:
iex> Dsv.Date.validate(~D[2020-10-10], min: ~D[2020-10-09])
:ok
iex> Dsv.Date.validate(~D[2020-10-10], min: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate(~D[2020-10-10], min: ~D[2020-10-11])
{:error, "Date is earlier than the minimum allowed date 2020-10-11"}
### max
`:max` example with first parameter as a string:
iex> Dsv.Date.validate("2020-10-10", max: ~D[2020-10-11])
:ok
iex> Dsv.Date.validate("2020-10-10", max: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate("2020-10-10", max: ~D[2020-10-09])
{:error, "Date is later than the maximum allowed date 2020-10-09"}
`:max` example with first parameter as a date:
iex> Dsv.Date.validate(~D[2020-10-10], max: ~D[2020-10-11])
:ok
iex> Dsv.Date.validate(~D[2020-10-10], max: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate(~D[2020-10-10], max: ~D[2020-10-09])
{:error, "Date is later than the maximum allowed date 2020-10-09"}
### min & max
`:min & :max` example:
iex> Dsv.Date.validate("2020-10-10", min: ~D[2020-10-09], max: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate("2020-10-09", min: ~D[2020-10-09], max: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate("2020-10-10", min: ~D[2020-10-09], max: ~D[2020-10-11])
:ok
iex> Dsv.Date.validate("2020-10-07", min: ~D[2020-10-08], max: ~D[2020-10-09])
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate("2020-10-10", min: ~D[2020-10-08], max: ~D[2020-10-09])
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate("2020-10-10", min: ~D[2020-10-10], max: ~D[2020-10-09])
** (RuntimeError) Min date (2020-10-10) can't be after max date (2020-10-09)
iex> Dsv.Date.validate(~D[2020-10-10], min: ~D[2020-10-09], max: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate(~D[2020-10-09], min: ~D[2020-10-09], max: ~D[2020-10-10])
:ok
iex> Dsv.Date.validate(~D[2020-10-10], min: ~D[2020-10-09], max: ~D[2020-10-11])
:ok
iex> Dsv.Date.validate(~D[2020-10-07], min: ~D[2020-10-08], max: ~D[2020-10-09])
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate(~D[2020-10-10], min: ~D[2020-10-08], max: ~D[2020-10-09])
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate(~D[2020-10-10], min: ~D[2020-10-10], max: ~D[2020-10-09])
** (RuntimeError) Min date (2020-10-10) can't be after max date (2020-10-09)
### range
`:range` example:
iex> Dsv.Date.validate("2020-10-10", range: {~D[2020-10-09], ~D[2020-10-10]})
:ok
iex> Dsv.Date.validate("2020-10-09", range: {~D[2020-10-09], ~D[2020-10-10]})
:ok
iex> Dsv.Date.validate("2020-10-10", range: {~D[2020-10-09], ~D[2020-10-11]})
:ok
iex> Dsv.Date.validate("2020-10-07", range: {~D[2020-10-08], ~D[2020-10-09]})
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate("2020-10-10", range: {~D[2020-10-08], ~D[2020-10-09]})
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate("2020-10-10", range: {~D[2020-10-10], ~D[2020-10-09]})
** (RuntimeError) Min date (2020-10-10) can't be after max date (2020-10-09)
iex> Dsv.Date.validate(~D[2020-10-10], range: {~D[2020-10-09], ~D[2020-10-10]})
:ok
iex> Dsv.Date.validate(~D[2020-10-09], range: {~D[2020-10-09], ~D[2020-10-10]})
:ok
iex> Dsv.Date.validate(~D[2020-10-10], range: {~D[2020-10-09], ~D[2020-10-11]})
:ok
iex> Dsv.Date.validate(~D[2020-10-07], range: {~D[2020-10-08], ~D[2020-10-09]})
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate(~D[2020-10-10], range: {~D[2020-10-08], ~D[2020-10-09]})
{:error, "Date must be between 2020-10-08 and 2020-10-09"}
iex> Dsv.Date.validate(~D[2020-10-10], range: {~D[2020-10-10], ~D[2020-10-09]})
** (RuntimeError) Min date (2020-10-10) can't be after max date (2020-10-09)
## Examples DateTime
### min
`:min` example:
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", min: ~U[2020-10-10 23:59:58Z])
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", min: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", min: ~U[2020-10-11 00:00:00Z])
{:error, "Date is earlier than the minimum allowed date 2020-10-11 00:00:00Z"}
iex> Dsv.Date.validate(~U[2020-10-10T23:59:59Z], min: ~U[2020-10-10 23:59:58Z])
:ok
iex> Dsv.Date.validate(~U[2020-10-10T23:59:59Z], min: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate(~U[2020-10-10T23:59:59Z], min: ~U[2020-10-11 00:00:00Z])
{:error, "Date is earlier than the minimum allowed date 2020-10-11 00:00:00Z"}
### max
`:max` example:
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", max: ~U[2020-10-11 00:00:00Z])
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", max: ~U[2020-10-10 23:59:58Z])
{:error, "Date is later than the maximum allowed date 2020-10-10 23:59:58Z"}
iex> Dsv.Date.validate(~U[2020-10-10T23:59:59Z], max: ~U[2020-10-11 00:00:00Z])
:ok
iex> Dsv.Date.validate(~U[2020-10-10T23:59:59Z], max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate(~U[2020-10-10T23:59:59Z], max: ~U[2020-10-10 23:59:58Z])
{:error, "Date is later than the maximum allowed date 2020-10-10 23:59:58Z"}
### min & max
`:min & :max` example:
iex> Dsv.Date.validate("2020-10-10T23:59:58Z", min: ~U[2020-10-10 23:59:58Z], max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", min: ~U[2020-10-10 23:59:58Z], max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:58Z", min: ~U[2020-10-10 23:59:57Z], max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:57Z", min: ~U[2020-10-10 23:59:58Z], max: ~U[2020-10-10 23:59:59Z])
{:error, "Date must be between 2020-10-10 23:59:58Z and 2020-10-10 23:59:59Z"}
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", min: ~U[2020-10-10 23:59:57Z], max: ~U[2020-10-10 23:59:58Z])
{:error, "Date must be between 2020-10-10 23:59:57Z and 2020-10-10 23:59:58Z"}
iex> Dsv.Date.validate("2020-10-10T23:59:58Z", min: ~U[2020-10-10 23:59:59Z], max: ~U[2020-10-10 23:59:58Z])
** (RuntimeError) Min date (2020-10-10 23:59:59Z) can't be after max date (2020-10-10 23:59:58Z)
iex> Dsv.Date.validate(~U[2020-10-10 23:59:58Z], min: ~U[2020-10-10 23:59:58Z], max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate(~U[2020-10-10 23:59:59Z], min: ~U[2020-10-10 23:59:58Z], max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate(~U[2020-10-10 23:59:58Z], min: ~U[2020-10-10 23:59:57Z], max: ~U[2020-10-10 23:59:59Z])
:ok
iex> Dsv.Date.validate(~U[2020-10-10 23:59:57Z], min: ~U[2020-10-10 23:59:58Z], max: ~U[2020-10-10 23:59:59Z])
{:error, "Date must be between 2020-10-10 23:59:58Z and 2020-10-10 23:59:59Z"}
iex> Dsv.Date.validate(~U[2020-10-10 23:59:59Z], min: ~U[2020-10-10 23:59:57Z], max: ~U[2020-10-10 23:59:58Z])
{:error, "Date must be between 2020-10-10 23:59:57Z and 2020-10-10 23:59:58Z"}
iex> Dsv.Date.validate(~U[2020-10-10 23:59:58Z], min: ~U[2020-10-10 23:59:59Z], max: ~U[2020-10-10 23:59:58Z])
** (RuntimeError) Min date (2020-10-10 23:59:59Z) can't be after max date (2020-10-10 23:59:58Z)
### range
`:range` example:
iex> Dsv.Date.validate("2020-10-10T23:59:58Z", range: {~U[2020-10-10 23:59:58Z], ~U[2020-10-10 23:59:59Z]})
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", range: {~U[2020-10-10 23:59:58Z], ~U[2020-10-10 23:59:59Z]})
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:58Z", range: {~U[2020-10-10 23:59:57Z], ~U[2020-10-10 23:59:59Z]})
:ok
iex> Dsv.Date.validate("2020-10-10T23:59:57Z", range: {~U[2020-10-10 23:59:58Z], ~U[2020-10-10 23:59:59Z]})
{:error, "Date must be between 2020-10-10 23:59:58Z and 2020-10-10 23:59:59Z"}
iex> Dsv.Date.validate("2020-10-10T23:59:59Z", range: {~U[2020-10-10 23:59:57Z], ~U[2020-10-10 23:59:58Z]})
{:error, "Date must be between 2020-10-10 23:59:57Z and 2020-10-10 23:59:58Z"}
iex> Dsv.Date.validate("2020-10-10T23:59:58Z", range: {~U[2020-10-10 23:59:59Z], ~U[2020-10-10 23:59:58Z]})
** (RuntimeError) Min date (2020-10-10 23:59:59Z) can't be after max date (2020-10-10 23:59:58Z)
iex> Dsv.Date.validate(~U[2020-10-10 23:59:58Z], range: {~U[2020-10-10 23:59:58Z], ~U[2020-10-10 23:59:59Z]})
:ok
iex> Dsv.Date.validate(~U[2020-10-10 23:59:59Z], range: {~U[2020-10-10 23:59:58Z], ~U[2020-10-10 23:59:59Z]})
:ok
iex> Dsv.Date.validate(~U[2020-10-10 23:59:58Z], range: {~U[2020-10-10 23:59:57Z], ~U[2020-10-10 23:59:59Z]})
:ok
iex> Dsv.Date.validate(~U[2020-10-10 23:59:57Z], range: {~U[2020-10-10 23:59:58Z], ~U[2020-10-10 23:59:59Z]})
{:error, "Date must be between 2020-10-10 23:59:58Z and 2020-10-10 23:59:59Z"}
iex> Dsv.Date.validate(~U[2020-10-10 23:59:59Z], range: {~U[2020-10-10 23:59:57Z], ~U[2020-10-10 23:59:58Z]})
{:error, "Date must be between 2020-10-10 23:59:57Z and 2020-10-10 23:59:58Z"}
iex> Dsv.Date.validate(~U[2020-10-10 23:59:58Z], [range: {~U[2020-10-10 23:59:59Z], ~U[2020-10-10 23:59:58Z]}])
** (RuntimeError) Min date (2020-10-10 23:59:59Z) can't be after max date (2020-10-10 23:59:58Z)
## Examples Time
### min
`:min` example:
iex> Dsv.Date.validate("23:59:59Z", min: ~T[23:59:58Z])
:ok
iex> Dsv.Date.validate("23:59:59Z", min: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate("23:59:58Z", min: ~T[23:59:59Z])
{:error, "Date is earlier than the minimum allowed date 23:59:59"}
iex> Dsv.Date.validate(~T[23:59:59Z], min: ~T[23:59:58Z])
:ok
iex> Dsv.Date.validate(~T[23:59:59Z], min: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate(~T[23:59:58Z], min: ~T[23:59:59Z])
{:error, "Date is earlier than the minimum allowed date 23:59:59"}
### max
`:max` example:
iex> Dsv.Date.validate("23:59:58Z", max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate("23:59:59Z", max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate("23:59:59Z", max: ~T[23:59:58Z])
{:error, "Date is later than the maximum allowed date 23:59:58"}
iex> Dsv.Date.validate(~T[23:59:58Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate(~T[23:59:59Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate(~T[23:59:59Z], max: ~T[23:59:58Z])
{:error, "Date is later than the maximum allowed date 23:59:58"}
### min & max
`:min & :max` example:
iex> Dsv.Date.validate("23:59:58Z", min: ~T[23:59:58Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate("23:59:59Z", min: ~T[23:59:58Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate("23:59:58Z", min: ~T[23:59:57Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate("23:59:57Z", min: ~T[23:59:58Z], max: ~T[23:59:59Z])
{:error, "Date must be between 23:59:58 and 23:59:59"}
iex> Dsv.Date.validate("23:59:59Z", min: ~T[23:59:57Z], max: ~T[23:59:58Z])
{:error, "Date must be between 23:59:57 and 23:59:58"}
iex> Dsv.Date.validate("23:59:58Z", min: ~T[23:59:59Z], max: ~T[23:59:58Z])
** (RuntimeError) Min date (23:59:59) can't be after max date (23:59:58)
iex> Dsv.Date.validate(~T[23:59:58Z], min: ~T[23:59:58Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate(~T[23:59:59Z], min: ~T[23:59:58Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate(~T[23:59:58Z], min: ~T[23:59:57Z], max: ~T[23:59:59Z])
:ok
iex> Dsv.Date.validate(~T[23:59:57Z], min: ~T[23:59:58Z], max: ~T[23:59:59Z])
{:error, "Date must be between 23:59:58 and 23:59:59"}
iex> Dsv.Date.validate(~T[23:59:59Z], min: ~T[23:59:57Z], max: ~T[23:59:58Z])
{:error, "Date must be between 23:59:57 and 23:59:58"}
iex> Dsv.Date.validate(~T[23:59:58Z], min: ~T[23:59:59Z], max: ~T[23:59:58Z])
** (RuntimeError) Min date (23:59:59) can't be after max date (23:59:58)
### range
`:range` example:
iex> Dsv.Date.validate("23:59:58Z", range: {~T[23:59:58Z], ~T[23:59:59Z]})
:ok
iex> Dsv.Date.validate("23:59:59Z", range: {~T[23:59:58Z], ~T[23:59:59Z]})
:ok
iex> Dsv.Date.validate("23:59:58Z", range: {~T[23:59:57Z], ~T[23:59:59Z]})
:ok
iex> Dsv.Date.validate("23:59:57Z", range: {~T[23:59:58Z], ~T[23:59:59Z]})
{:error, "Date must be between 23:59:58 and 23:59:59"}
iex> Dsv.Date.validate("23:59:59Z", range: {~T[23:59:57Z], ~T[23:59:58Z]})
{:error, "Date must be between 23:59:57 and 23:59:58"}
iex> Dsv.Date.validate("23:59:58Z", range: {~T[23:59:59Z], ~T[23:59:58Z]})
** (RuntimeError) Min date (23:59:59) can't be after max date (23:59:58)
iex> Dsv.Date.validate(~T[23:59:58Z], range: {~T[23:59:58Z], ~T[23:59:59Z]})
:ok
iex> Dsv.Date.validate(~T[23:59:59Z], range: {~T[23:59:58Z], ~T[23:59:59Z]})
:ok
iex> Dsv.Date.validate(~T[23:59:58Z], range: {~T[23:59:57Z], ~T[23:59:59Z]})
:ok
iex> Dsv.Date.validate(~T[23:59:57Z], range: {~T[23:59:58Z], ~T[23:59:59Z]})
{:error, "Date must be between 23:59:58 and 23:59:59"}
iex> Dsv.Date.validate(~T[23:59:59Z], range: {~T[23:59:57Z], ~T[23:59:58Z]})
{:error, "Date must be between 23:59:57 and 23:59:58"}
iex> Dsv.Date.validate(~T[23:59:58Z], range: {~T[23:59:59Z], ~T[23:59:58Z]})
** (RuntimeError) Min date (23:59:59) can't be after max date (23:59:58)
"""
@spec validate(Date | DateTime | Time | NaiveDateTime | String.t(), keyword()) ::
:ok | {:error, String.t()}
def validate(data, options), do: super(data, options)
end