zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

timestamptz.ex (2555B)


      1 defmodule Postgrex.Extensions.TimestampTZ do
      2   @moduledoc false
      3   import Postgrex.BinaryUtils, warn: false
      4   use Postgrex.BinaryExtension, send: "timestamptz_send"
      5 
      6   @gs_epoch NaiveDateTime.to_gregorian_seconds(~N[2000-01-01 00:00:00.0]) |> elem(0)
      7 
      8   @gs_unix_epoch NaiveDateTime.to_gregorian_seconds(~N[1970-01-01 00:00:00.0]) |> elem(0)
      9   @us_epoch (@gs_epoch - @gs_unix_epoch) * 1_000_000
     10 
     11   @gs_max elem(NaiveDateTime.to_gregorian_seconds(~N[9999-01-01 00:00:00.0]), 0) - @gs_unix_epoch
     12   @us_max @gs_max * 1_000_000
     13 
     14   @gs_min elem(NaiveDateTime.to_gregorian_seconds(~N[-4713-01-01 00:00:00.0]), 0) - @gs_unix_epoch
     15   @us_min @gs_min * 1_000_000
     16 
     17   @plus_infinity 9_223_372_036_854_775_807
     18   @minus_infinity -9_223_372_036_854_775_808
     19 
     20   def init(opts), do: Keyword.get(opts, :allow_infinite_timestamps, false)
     21 
     22   def encode(_) do
     23     quote location: :keep do
     24       %DateTime{calendar: Calendar.ISO} = dt ->
     25         unquote(__MODULE__).encode_elixir(dt)
     26 
     27       other ->
     28         raise DBConnection.EncodeError,
     29               Postgrex.Utils.encode_msg(other, DateTime)
     30     end
     31   end
     32 
     33   def decode(infinity?) do
     34     quote location: :keep do
     35       <<8::int32(), microsecs::int64()>> ->
     36         unquote(__MODULE__).microsecond_to_elixir(microsecs, unquote(infinity?))
     37     end
     38   end
     39 
     40   ## Helpers
     41 
     42   def encode_elixir(%DateTime{utc_offset: 0, std_offset: 0} = datetime) do
     43     case DateTime.to_unix(datetime, :microsecond) do
     44       microsecs when microsecs in @us_min..@us_max ->
     45         <<8::int32(), microsecs - @us_epoch::int64()>>
     46 
     47       _ ->
     48         raise ArgumentError, "#{inspect(datetime)} is not in the year range -4713..9999"
     49     end
     50   end
     51 
     52   def encode_elixir(%DateTime{} = datetime) do
     53     raise ArgumentError, "#{inspect(datetime)} is not in UTC"
     54   end
     55 
     56   def microsecond_to_elixir(@plus_infinity, infinity?) do
     57     if infinity?, do: :inf, else: raise_infinity("infinity")
     58   end
     59 
     60   def microsecond_to_elixir(@minus_infinity, infinity?) do
     61     if infinity?, do: :"-inf", else: raise_infinity("-infinity")
     62   end
     63 
     64   def microsecond_to_elixir(microsecs, _infinity) do
     65     DateTime.from_unix!(microsecs + @us_epoch, :microsecond)
     66   end
     67 
     68   defp raise_infinity(type) do
     69     raise ArgumentError, """
     70     got \"#{type}\" from PostgreSQL. If you want to support infinity timestamps \
     71     in your application, you can enable them by defining your own types:
     72 
     73         Postgrex.Types.define(MyApp.PostgrexTypes, [], allow_infinite_timestamps: true)
     74 
     75     And then configuring your database to use it:
     76 
     77         types: MyApp.PostgrexTypes
     78     """
     79   end
     80 end