zf

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

timestamp.ex (2783B)


      1 defmodule Postgrex.Extensions.Timestamp do
      2   @moduledoc false
      3   import Postgrex.BinaryUtils, warn: false
      4   use Postgrex.BinaryExtension, send: "timestamp_send"
      5 
      6   @gs_epoch NaiveDateTime.to_gregorian_seconds(~N[2000-01-01 00:00:00]) |> elem(0)
      7   @max_year 294_276
      8   @min_year -4_713
      9   @plus_infinity 9_223_372_036_854_775_807
     10   @minus_infinity -9_223_372_036_854_775_808
     11 
     12   def init(opts), do: Keyword.get(opts, :allow_infinite_timestamps, false)
     13 
     14   def encode(_) do
     15     quote location: :keep do
     16       %NaiveDateTime{calendar: Calendar.ISO} = naive ->
     17         unquote(__MODULE__).encode_elixir(naive)
     18 
     19       %DateTime{calendar: Calendar.ISO} = dt ->
     20         unquote(__MODULE__).encode_elixir(dt)
     21 
     22       other ->
     23         raise DBConnection.EncodeError,
     24               Postgrex.Utils.encode_msg(other, {DateTime, NaiveDateTime})
     25     end
     26   end
     27 
     28   def decode(infinity?) do
     29     quote location: :keep do
     30       <<8::int32(), microsecs::int64()>> ->
     31         unquote(__MODULE__).microsecond_to_elixir(microsecs, unquote(infinity?))
     32     end
     33   end
     34 
     35   ## Helpers
     36 
     37   def encode_elixir(
     38         %_{
     39           year: year,
     40           hour: hour,
     41           minute: min,
     42           second: sec,
     43           microsecond: {usec, _}
     44         } = date_time
     45       )
     46       when year <= @max_year and year >= @min_year and hour in 0..23 and min in 0..59 and
     47              sec in 0..59 and
     48              usec in 0..999_999 do
     49     {gregorian_seconds, usec} = NaiveDateTime.to_gregorian_seconds(date_time)
     50     secs = gregorian_seconds - @gs_epoch
     51     <<8::int32(), secs * 1_000_000 + usec::int64()>>
     52   end
     53 
     54   def microsecond_to_elixir(@plus_infinity, infinity?) do
     55     if infinity?, do: :inf, else: raise_infinity("infinity")
     56   end
     57 
     58   def microsecond_to_elixir(@minus_infinity, infinity?) do
     59     if infinity?, do: :"-inf", else: raise_infinity("-infinity")
     60   end
     61 
     62   def microsecond_to_elixir(microsecs, _infinity) do
     63     split(microsecs)
     64   end
     65 
     66   defp split(microsecs) when microsecs < 0 and rem(microsecs, 1_000_000) != 0 do
     67     secs = div(microsecs, 1_000_000) - 1
     68     microsecs = 1_000_000 + rem(microsecs, 1_000_000)
     69     split(secs, microsecs)
     70   end
     71 
     72   defp split(microsecs) do
     73     secs = div(microsecs, 1_000_000)
     74     microsecs = rem(microsecs, 1_000_000)
     75     split(secs, microsecs)
     76   end
     77 
     78   defp split(secs, microsecs) do
     79     NaiveDateTime.from_gregorian_seconds(secs + @gs_epoch, {microsecs, 6})
     80   end
     81 
     82   defp raise_infinity(type) do
     83     raise ArgumentError, """
     84     got \"#{type}\" from PostgreSQL. If you want to support infinity timestamps \
     85     in your application, you can enable them by defining your own types:
     86 
     87         Postgrex.Types.define(MyApp.PostgrexTypes, [], allow_infinite_timestamps: true)
     88 
     89     And then configuring your database to use it:
     90 
     91         types: MyApp.PostgrexTypes
     92     """
     93   end
     94 end