diff options
author | José Valim <jose.valim@plataformatec.com.br> | 2016-09-15 10:09:31 +0200 |
---|---|---|
committer | José Valim <jose.valim@plataformatec.com.br> | 2016-09-15 10:09:31 +0200 |
commit | 8d2c5baa9be62dedec2b2702d5e26de6f803dcf2 (patch) | |
tree | ac79354c4e3dd7bd7db461f598561e12cef2d263 | |
parent | e50735ff2a7c16cc7705d8fa59af906e986c19f7 (diff) | |
download | elixir-8d2c5baa9be62dedec2b2702d5e26de6f803dcf2.tar.gz |
Add DateTime.from_naive/2
-rw-r--r-- | lib/elixir/lib/calendar.ex | 113 | ||||
-rw-r--r-- | lib/elixir/lib/calendar/iso.ex | 4 | ||||
-rw-r--r-- | lib/elixir/test/elixir/calendar_test.exs | 3 |
3 files changed, 66 insertions, 54 deletions
diff --git a/lib/elixir/lib/calendar.ex b/lib/elixir/lib/calendar.ex index 87a34e4c8..750bf736d 100644 --- a/lib/elixir/lib/calendar.ex +++ b/lib/elixir/lib/calendar.ex @@ -111,7 +111,7 @@ defmodule Date do ## Examples - iex> date = Time.utc_now() + iex> date = Date.utc_today() iex> date.year >= 2016 true @@ -661,7 +661,7 @@ defmodule NaiveDateTime do ## Examples iex> NaiveDateTime.from_unix(1464096368) - {:ok, ~N[2015-05-25 13:26:08]} + {:ok, ~N[2016-05-24 13:26:08]} iex> NaiveDateTime.from_unix(1432560368868569, :microseconds) {:ok, ~N[2015-05-25 13:26:08.868569]} @@ -670,13 +670,13 @@ defmodule NaiveDateTime do iex> NaiveDateTime.from_unix(1432560368868569, 1024) {:ok, %NaiveDateTime{calendar: Calendar.ISO, day: 23, hour: 22, microsecond: {211914, 3}, - minute: 53, month: 1, second: 43, year: 46302, zone_abbr: "UTC"}} + minute: 53, month: 1, second: 43, year: 46302}} Negative Unix times are supported, up to -#{@unix_epoch} seconds, which is equivalent to "0000-01-01T00:00:00Z" or 0 gregorian seconds. iex> NaiveDateTime.from_unix(-12345678910) - {:ok, ~N[1578-10-13 04:10:50]} + {:ok, ~N[1578-10-13 04:44:50]} When a Unix time before that moment is passed to `from_unix/2`, `:error` will be returned. """ @@ -684,11 +684,10 @@ defmodule NaiveDateTime do def from_unix(integer, unit \\ :seconds) when is_integer(integer) do case Calendar.ISO.from_unix(integer, unit) do {:ok, {year, month, day}, {hour, minute, second}, microsecond} -> - {:ok, %DateTime{year: year, month: month, day: day, - hour: hour, minute: minute, second: second, microsecond: microsecond, - std_offset: 0, utc_offset: 0, zone_abbr: "UTC", time_zone: "Etc/UTC"}} - :error -> - :error + {:ok, %NaiveDateTime{year: year, month: month, day: day, + hour: hour, minute: minute, second: second, microsecond: microsecond}} + {:error, _} = error -> + error end end @@ -707,7 +706,7 @@ defmodule NaiveDateTime do ## Examples iex> NaiveDateTime.from_unix!(1464096368) - ~N[2015-05-25 13:26:08] + ~N[2016-05-24 13:26:08] iex> NaiveDateTime.from_unix!(1432560368868569, :microseconds) ~N[2015-05-25 13:26:08.868569] @@ -716,7 +715,7 @@ defmodule NaiveDateTime do which is equivalent to "0000-01-01T00:00:00Z" or 0 gregorian seconds. iex> NaiveDateTime.from_unix!(-12345678910) - ~N[1578-10-13 04:10:50] + ~N[1578-10-13 04:44:50] When a Unix time before that moment is passed to `from_unix/2`, `:error` will be returned. """ @@ -725,46 +724,12 @@ defmodule NaiveDateTime do case from_unix(integer, unit) do {:ok, datetime} -> datetime - :error -> + {:error, :invalid_unix_time} -> raise ArgumentError, "invalid Unix time #{integer}" end end @doc """ - Converts the given NaiveDateTime to Unix seconds. - - The NaiveDateTime is expected to be using the ISO calendar - with a year greater than or equal to 0. - - It will return the integer with the given unit, - according to `System.convert_time_unit/3`. - - WARNING: A Unix time is always in UTC. However, NaiveDateTime - does not have time zone information, which means there is no - guarantee the Unix time retrieved is the one originally intended. - This may result in incorrect results. Prefer using `DateTime` - when converting to and from Unix time as it includes the time - zone data. - - ## Examples - - iex> 1464096368 |> NaiveDateTime.from_unix!() |> NaiveDateTime.to_unix() - 1464096368 - - iex> NaiveDateTime.to_unix(~N[2015-05-25 13:26:08]) - 1464096368 - - """ - @spec to_unix(NaiveDateTime.t, System.time_unit) :: non_neg_integer - def to_unix(datetime, unit \\ :seconds) - - def to_unix(%NaiveDateTime{calendar: Calendar.ISO, year: year, month: month, day: day, - hour: hour, minute: minute, second: second, microsecond: {microsecond, _}}, unit) when year >= 0 do - seconds = :calendar.datetime_to_gregorian_seconds({{year, month, day}, {hour, minute, second}}) - System.convert_time_unit((seconds - @unix_epoch) * 1_000_000 + microsecond, :microseconds, unit) - end - - @doc """ Builds a new ISO naive date time. Expects all values to be integers. Returns `{:ok, naive_date_time}` @@ -1170,15 +1135,15 @@ defmodule DateTime do When a Unix time before that moment is passed to `from_unix/2`, `:error` will be returned. """ - @spec from_unix(integer, :native | System.time_unit) :: {:ok, DateTime.t} + @spec from_unix(integer, :native | System.time_unit) :: {:ok, DateTime.t} | {:error, atom} def from_unix(integer, unit \\ :seconds) when is_integer(integer) do case Calendar.ISO.from_unix(integer, unit) do {:ok, {year, month, day}, {hour, minute, second}, microsecond} -> {:ok, %DateTime{year: year, month: month, day: day, hour: hour, minute: minute, second: second, microsecond: microsecond, std_offset: 0, utc_offset: 0, zone_abbr: "UTC", time_zone: "Etc/UTC"}} - :error -> - :error + {:error, _} = error -> + error end end @@ -1219,12 +1184,60 @@ defmodule DateTime do case from_unix(integer, unit) do {:ok, datetime} -> datetime - :error -> + {:error, :invalid_unix_time} -> raise ArgumentError, "invalid Unix time #{integer}" end end @doc """ + Converts the given NaiveDateTime to DateTime. + + It expects a timezone to put the NaiveDateTime in. + Currently it only supports "Etc/UTC" as timezone. + + ## Examples + + iex> DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC") + {:ok, %DateTime{calendar: Calendar.ISO, day: 24, hour: 13, microsecond: {3000, 3}, minute: 26, + month: 5, second: 8, std_offset: 0, time_zone: "Etc/UTC", utc_offset: 0, + year: 2016, zone_abbr: "UTC"}} + + """ + @spec from_naive(NaiveDateTime.t, Calendar.time_zone) :: {:ok, DateTime.t} + def from_naive(naive_datetime, time_zone) + + def from_naive(%NaiveDateTime{hour: hour, minute: minute, second: second, microsecond: microsecond, + year: year, month: month, day: day}, "Etc/UTC") do + {:ok, %DateTime{year: year, month: month, day: day, + hour: hour, minute: minute, second: second, microsecond: microsecond, + std_offset: 0, utc_offset: 0, zone_abbr: "UTC", time_zone: "Etc/UTC"}} + end + + @doc """ + Converts the given NaiveDateTime to DateTime. + + It expects a timezone to put the NaiveDateTime in. + Currently it only supports "Etc/UTC" as timezone. + + ## Examples + + iex> DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") + %DateTime{calendar: Calendar.ISO, day: 24, hour: 13, microsecond: {3000, 3}, minute: 26, + month: 5, second: 8, std_offset: 0, time_zone: "Etc/UTC", utc_offset: 0, + year: 2016, zone_abbr: "UTC"} + + """ + @spec from_naive!(non_neg_integer, :native | System.time_unit) :: DateTime.t + def from_naive!(naive_datetime, time_zone) do + case from_naive(naive_datetime, time_zone) do + {:ok, datetime} -> + datetime + {:error, reason} -> + raise ArgumentError, "cannot parse #{inspect naive_datetime} to datetime, reason: #{inspect reason}" + end + end + + @doc """ Converts the given DateTime to Unix seconds. The DateTime is expected to be using the ISO calendar diff --git a/lib/elixir/lib/calendar/iso.ex b/lib/elixir/lib/calendar/iso.ex index 93b40f69a..20b4bddde 100644 --- a/lib/elixir/lib/calendar/iso.ex +++ b/lib/elixir/lib/calendar/iso.ex @@ -10,6 +10,7 @@ defmodule Calendar.ISO do """ @behaviour Calendar + @unix_epoch :calendar.datetime_to_gregorian_seconds {{1970, 1, 1}, {0, 0, 0}} @doc """ Builds and validates an ISO date. @@ -37,7 +38,6 @@ defmodule Calendar.ISO do end end - @doc """ Returns the last day of the month for the given year. @@ -154,7 +154,7 @@ defmodule Calendar.ISO do def from_unix(integer, unit) when is_integer(integer) do total = System.convert_time_unit(integer, unit, :microseconds) if total < -@unix_epoch * 1_000_000 do - :error + {:error, :invalid_unix_time} else microsecond = rem(total, 1_000_000) precision = precision_for_unit(unit) diff --git a/lib/elixir/test/elixir/calendar_test.exs b/lib/elixir/test/elixir/calendar_test.exs index a5afd6d0b..8a3c0ea10 100644 --- a/lib/elixir/test/elixir/calendar_test.exs +++ b/lib/elixir/test/elixir/calendar_test.exs @@ -77,8 +77,7 @@ defmodule DateTimeTest do utc_offset: 0, year: 0, zone_abbr: "UTC" } assert DateTime.from_unix(-62167219200) == {:ok, datetime} - - assert DateTime.from_unix(-62167219201) == :error + assert DateTime.from_unix(-62167219201) == {:error, :invalid_unix_time} end test "from_unix!/2" do |