Skip to content

Commit

Permalink
Fix specs
Browse files Browse the repository at this point in the history
  • Loading branch information
kipcole9 committed Aug 15, 2024
2 parents 49f9b73 + f62d414 commit 4b1aa9a
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 52 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

**Note that `ex_cldr_calendars` version 1.24.0 and later are supported on Elixir 1.12 and later only.**

## Cldr.Calendars v1.26.0

This is the changelog for Cldr Calendars v1.26.0 released on July 27th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_calendars/tags)

### Bug Fixes

* Microseconds in `t:Cldr.Calendar.Duration.t/0` now follow the `t:Time.t/0` expectations.

### Enhancements

* Adds `Cldr.Calendar.Duration.new_from_seconds/1`

## Cldr.Calendars v1.25.2

This is the changelog for Cldr Calendars v1.25.2 released on July 9th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_calendars/tags)
Expand Down
10 changes: 7 additions & 3 deletions lib/cldr/calendar.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2377,10 +2377,14 @@ defmodule Cldr.Calendar do
@doc since: "1.19.0"

@spec localize(any_date_time()) ::
{:ok, any_date_time()} | {:error, :incompatible_calendars} | {:error, {module(), String.t()}}
{:ok, any_date_time()}
| {:error, :incompatible_calendars}
| {:error, {module(), String.t()}}

@spec localize(any_date_time(), Keyword.t() | atom()) ::
{:ok, any_date_time()} | {:error, :incompatible_calendars} | {:error, {module(), String.t()}}
{:ok, any_date_time()}
| {:error, :incompatible_calendars}
| {:error, {module(), String.t()}}

@spec localize(any_date_time(), atom(), Keyword.t()) ::
String.t() | {:error, :incompatible_calendars} | {:error, {module(), String.t()}}
Expand Down Expand Up @@ -2478,7 +2482,7 @@ defmodule Cldr.Calendar do
"""
@spec localize(datetime :: any_date_time(), part :: part(), options :: Keyword.t()) ::
String.t() | [day_of_week_to_binary()] | {:error, {module(), String.t()}}
String.t() | {:error, {module(), String.t()}}

def localize(datetime, part, options \\ [])

Expand Down
8 changes: 6 additions & 2 deletions lib/cldr/calendar/backend/calendar.ex
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,14 @@ defmodule Cldr.Calendar.Backend do
@doc since: "1.25.0"

@spec localize(Cldr.Calendar.any_date_time()) ::
{:ok, Elixir.Date.t()} | {:error, :incompatible_calendars} | {:error, {module(), String.t()}}
{:ok, Elixir.Date.t()}
| {:error, :incompatible_calendars}
| {:error, {module(), String.t()}}

@spec localize(Cldr.Calendar.any_date_time(), Keyword.t() | Cldr.Calendar.part()) ::
{:ok, Elixir.Date.t()} | {:error, :incompatible_calendars} | {:error, {module(), String.t()}}
{:ok, Elixir.Date.t()}
| {:error, :incompatible_calendars}
| {:error, {module(), String.t()}}

@spec localize(Cldr.Calendar.any_date_time(), Cldr.Calendar.part(), Keyword.t()) ::
String.t() | {:error, :incompatible_calendars} | {:error, {module(), String.t()}}
Expand Down
113 changes: 99 additions & 14 deletions lib/cldr/calendar/duration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defmodule Cldr.Calendar.Duration do
"""

@struct_list [year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0, microsecond: 0]
@struct_list [year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0, microsecond: {0, 6}]
@keys Keyword.keys(@struct_list)
defstruct @struct_list

Expand All @@ -41,7 +41,7 @@ defmodule Cldr.Calendar.Duration do
hour: non_neg_integer(),
minute: non_neg_integer(),
second: non_neg_integer(),
microsecond: non_neg_integer()
microsecond: {integer(), 1..6}
}

@typedoc "A date, time, naivedatetime or datetime"
Expand Down Expand Up @@ -108,7 +108,10 @@ defmodule Cldr.Calendar.Duration do
def to_string(%__MODULE__{} = duration, options \\ []) do
{except, options} = Keyword.pop(options, :except, [])

for key <- @keys, value = Map.get(duration, key), value != 0 && key not in except do
for key <- @keys,
value = Map.get(duration, key),
maybe_extract_microseconds(key, value) != 0 && key not in except do
value = maybe_extract_microseconds(key, value)
Cldr.Unit.new!(key, value)
end
|> Cldr.Unit.to_string(options)
Expand Down Expand Up @@ -154,7 +157,10 @@ defmodule Cldr.Calendar.Duration do
except = Keyword.get(options, :except, [])

formatted =
for key <- @keys, value = Map.get(duration, key), value != 0 && key not in except do
for key <- @keys,
value = Map.get(duration, key),
maybe_extract_microseconds(key, value) != 0 && key not in except do
value = maybe_extract_microseconds(key, value)
if value > 1, do: "#{value} #{key}s", else: "#{value} #{key}"
end
|> Enum.join(", ")
Expand All @@ -163,6 +169,9 @@ defmodule Cldr.Calendar.Duration do
end
end

defp maybe_extract_microseconds(:microsecond, {microseconds, _precision}), do: microseconds
defp maybe_extract_microseconds(_any, value), do: value

@doc """
Formats a duration as a string or raises
an exception on error.
Expand Down Expand Up @@ -233,7 +242,7 @@ defmodule Cldr.Calendar.Duration do
month: 11,
day: 30,
hour: 0,
microsecond: 0,
microsecond: {0, 6},
minute: 0,
second: 0
}}
Expand Down Expand Up @@ -272,7 +281,7 @@ defmodule Cldr.Calendar.Duration do
hour: hours,
minute: minutes,
second: seconds,
microsecond: microseconds
microsecond: microsecond_precision(microseconds)
)}
end
end
Expand Down Expand Up @@ -311,16 +320,16 @@ defmodule Cldr.Calendar.Duration do
month: 11,
day: 30,
hour: 0,
microsecond: 0,
microsecond: {0, 6},
minute: 0,
second: 0
}}
"""
@spec new(interval()) :: {:ok, t()} | {:error, {module(), String.t()}}
@spec new(interval :: interval()) :: {:ok, t()} | {:error, {module(), String.t()}}

if Code.ensure_loaded?(CalendarInterval) do
def new(%CalendarInterval{first: first, last: last, precision: precision})
def new(%CalendarInterval{first: first, last: last, precision: precision} = _interval)
when precision in [:year, :month, :day] do
first = %{first | hour: 0, minute: 0, second: 0, microsecond: {0, 6}}
last = %{last | hour: 0, minute: 0, second: 0, microsecond: {0, 6}}
Expand Down Expand Up @@ -354,6 +363,82 @@ defmodule Cldr.Calendar.Duration do
"The two dates must be in the same calendar. Found #{inspect(from)} and #{inspect(to)}"}}
end

@doc """
Returns a duration calculated from a number of seconds.
The duration will be calculated in hours, minutes,
seconds and microseconds only.
### Arguments
* `seconds` is a number of seconds as a float or
integer.
### Returns
* a `t:Cldr.Calendar.Duration.t/0`
### Example
iex> Cldr.Calendar.Duration.new_from_seconds(36092.1)
%Cldr.Calendar.Duration{
year: 0,
month: 0,
day: 0,
hour: 10,
minute: 1,
second: 32,
microsecond: {100000, 1}
}
"""
@doc since: "1.26.0"
@spec new_from_seconds(seconds :: number()) :: t()
def new_from_seconds(seconds) when is_number(seconds) do
microseconds = microseconds_from_fraction(seconds)
seconds = trunc(seconds)
hours = div(seconds, 3600)
remainder = rem(seconds, 3600)
minutes = div(remainder, 60)
seconds = rem(remainder, 60)

%__MODULE__{
year: 0,
month: 0,
day: 0,
hour: hours,
minute: minutes,
second: seconds,
microsecond: microseconds
}
end

defp microseconds_from_fraction(number) do
fraction = Cldr.Digits.fraction_as_integer(number)

cond do
fraction == 0 -> {0, 6}
fraction < 10 -> {fraction * 100_000, 1}
fraction < 100 -> {fraction * 10_000, 2}
fraction < 1_000 -> {fraction * 1_000, 3}
fraction < 10_000 -> {fraction * 100, 4}
fraction < 100_000 -> {fraction * 10, 5}
fraction <= 1_000_000 -> {fraction, 6}
end
end

defp microsecond_precision(microseconds) do
cond do
microseconds == 0 -> {0, 6}
microseconds < 10 -> {microseconds, 1}
microseconds < 100 -> {microseconds, 2}
microseconds < 1_000 -> {microseconds, 3}
microseconds < 10_000 -> {microseconds, 4}
microseconds < 100_000 -> {microseconds, 5}
microseconds <= 1_000_000 -> {microseconds, 6}
end
end

defp cast_date_time(unquote(Cldr.Calendar.datetime()) = datetime) do
_ = calendar
{:ok, datetime}
Expand Down Expand Up @@ -430,7 +515,7 @@ defmodule Cldr.Calendar.Duration do
## Returns
* A `duration` struct or
* A `t:Cldr.Calendar.Duration.t/0` struct or
* raises an exception
Expand All @@ -442,7 +527,7 @@ defmodule Cldr.Calendar.Duration do
month: 11,
day: 30,
hour: 0,
microsecond: 0,
microsecond: {0, 6},
minute: 0,
second: 0
}
Expand Down Expand Up @@ -474,7 +559,7 @@ defmodule Cldr.Calendar.Duration do
## Returns
* A `duration` struct or
* A `t:Cldr.Calendar.Duration.t/0` struct or
* raises an exception
Expand All @@ -492,7 +577,7 @@ defmodule Cldr.Calendar.Duration do
month: 11,
day: 30,
hour: 0,
microsecond: 0,
microsecond: {0, 6},
minute: 0,
second: 0
}
Expand Down Expand Up @@ -592,6 +677,6 @@ defmodule Cldr.Calendar.Duration do
|> Map.put(:hour, hours)
|> Map.put(:minute, minutes)
|> Map.put(:second, seconds)
|> Map.put(:microsecond, microseconds)
|> Map.put(:microsecond, microsecond_precision(microseconds))
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Cldr.Calendar.MixProject do
use Mix.Project

@version "1.25.2"
@version "1.26.0"

def project do
[
Expand Down
4 changes: 0 additions & 4 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"benchee": {:hex, :benchee, "1.3.1", "c786e6a76321121a44229dde3988fc772bca73ea75170a73fd5f4ddf1af95ccf", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "76224c58ea1d0391c8309a8ecbfe27d71062878f59bd41a390266bf4ac1cc56d"},
"calendar_interval": {:hex, :calendar_interval, "0.2.0", "2b253b1e37ee1d4344639a3cbfb12abd0e996e4a8181537eb33c3e93fdfaffd9", [:mix], [], "hexpm", "c13d5e0108e61808a38f622987e1c5e881d96d28945213d3efe6dd06c28ba7b0"},
"cldr_utils": {:hex, :cldr_utils, "2.28.1", "3d85c835e1d0b7bceb9feed1647025ff7df59180246f13b582422f12b1afd52c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "79a5f645481d09b1372962384aa275d67d69273e73e3b38a9fee363eb57c2b79"},
"coerce": {:hex, :coerce, "1.0.1", "211c27386315dc2894ac11bc1f413a0e38505d808153367bd5c6e75a4003d096", [:mix], [], "hexpm", "b44a691700f7a1a15b4b7e2ff1fa30bebd669929ac8aa43cffe9e2f8bf051cf1"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
Expand All @@ -20,9 +19,6 @@
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"nimble_strftime": {:hex, :nimble_strftime, "0.1.1", "b988184d1bd945bc139b2c27dd00a6c0774ec94f6b0b580083abd62d5d07818b", [:mix], [], "hexpm", "89e599c9b8b4d1203b7bb5c79eb51ef7c6a28fbc6228230b312f8b796310d755"},
"numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"},
"ratio": {:hex, :ratio, "3.0.2", "60a5976872a4dc3d873ecc57eed1738589e99d1094834b9c935b118231297cfb", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "3a13ed5a30ad0bfd7e4a86bf86d93d2b5a06f5904417d38d3f3ea6406cdfc7bb"},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
"stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"},
"tz": {:hex, :tz, "0.27.1", "d8091d0c2d4f590e010c94830c3d842f548b4872a5b92028d74f0d0a3887aebe", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "215c9120dab5b7f7db4c93e91085c290b2efe478e147d84285a6583fd220727f"},
Expand Down
Loading

0 comments on commit 4b1aa9a

Please sign in to comment.