date.ex (1506B)
1 defmodule Postgrex.Extensions.Date do 2 @moduledoc false 3 import Postgrex.BinaryUtils, warn: false 4 use Postgrex.BinaryExtension, send: "date_send" 5 6 @gd_epoch Date.to_gregorian_days(~D[2000-01-01]) 7 @max_year 9999 8 9 # Latest date supported by Elixir. Postgresql 10 # supports later dates. 11 @max_days Date.to_gregorian_days(~D[9999-12-31]) 12 13 # Elixir supports earlier dates but this is the 14 # earliest supported in Postgresql. 15 @min_days Date.to_gregorian_days(~D[-4713-01-01]) 16 17 def encode(_) do 18 quote location: :keep do 19 %Date{calendar: Calendar.ISO} = date -> 20 unquote(__MODULE__).encode_elixir(date) 21 22 other -> 23 raise DBConnection.EncodeError, Postgrex.Utils.encode_msg(other, Date) 24 end 25 end 26 27 def decode(_) do 28 quote location: :keep do 29 <<4::int32(), days::int32()>> -> 30 unquote(__MODULE__).day_to_elixir(days) 31 end 32 end 33 34 ## Helpers 35 36 def encode_elixir(%Date{year: year} = date) when year <= @max_year do 37 <<4::int32(), Date.to_gregorian_days(date) - @gd_epoch::int32()>> 38 end 39 40 def encode_elixir(%Date{} = date) do 41 raise ArgumentError, "#{inspect(date)} is beyond the maximum year #{@max_year}" 42 end 43 44 def day_to_elixir(days) do 45 days = days + @gd_epoch 46 47 if days in @min_days..@max_days do 48 Date.from_gregorian_days(days) 49 else 50 raise ArgumentError, 51 "Postgrex can only decode dates with days between #{@min_days} and #{@max_days}, " <> 52 "got: #{inspect(days)}" 53 end 54 end 55 end