epgsql_idatetime.erl 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. %%% Copyright (C) 2008 - Will Glozer. All rights reserved.
  2. -module(epgsql_idatetime).
  3. -export([decode/2, encode/2]).
  4. -export([j2date/1, date2j/1]).
  5. -include("protocol.hrl").
  6. -define(POSTGRES_EPOC_JDATE, 2451545).
  7. -define(POSTGRES_EPOC_USECS, 946684800000000).
  8. -define(MINS_PER_HOUR, 60).
  9. -define(SECS_PER_MINUTE, 60).
  10. -define(USECS_PER_DAY, 86400000000).
  11. -define(USECS_PER_HOUR, 3600000000).
  12. -define(USECS_PER_MINUTE, 60000000).
  13. -define(USECS_PER_SEC, 1000000).
  14. decode(date, <<J:?int32>>) -> j2date(?POSTGRES_EPOC_JDATE + J);
  15. decode(time, <<N:?int64>>) -> i2time(N);
  16. decode(timetz, <<N:?int64, TZ:?int32>>) -> {i2time(N), TZ};
  17. decode(timestamp, <<N:?int64>>) -> i2timestamp(N);
  18. decode(timestamptz, <<N:?int64>>) -> i2timestamp(N);
  19. decode(interval, <<N:?int64, D:?int32, M:?int32>>) -> {i2time(N), D, M}.
  20. encode(date, D) -> <<(date2j(D) - ?POSTGRES_EPOC_JDATE):?int32>>;
  21. encode(time, T) -> <<(time2i(T)):?int64>>;
  22. encode(timetz, {T, TZ}) -> <<(time2i(T)):?int64, TZ:?int32>>;
  23. encode(timestamp, TS = {_, _, _}) -> <<(now2i(TS)):?int64>>;
  24. encode(timestamp, TS) -> <<(timestamp2i(TS)):?int64>>;
  25. encode(timestamptz, TS = {_, _, _}) -> <<(now2i(TS)):?int64>>;
  26. encode(timestamptz, TS) -> <<(timestamp2i(TS)):?int64>>;
  27. encode(interval, {T, D, M}) -> <<(time2i(T)):?int64, D:?int32, M:?int32>>.
  28. %% Julian calendar
  29. %% See $PG$/src/backend/utils/adt/datetime.c
  30. j2date(N) ->
  31. J = N + 32044,
  32. Q1 = J div 146097,
  33. Extra = (J - Q1 * 146097) * 4 + 3,
  34. J2 = J + 60 + Q1 * 3 + Extra div 146097,
  35. Q2 = J2 div 1461,
  36. J3 = J2 - Q2 * 1461,
  37. Y = J3 * 4 div 1461,
  38. J4 = case Y of
  39. 0 -> ((J3 + 306) rem 366) + 123;
  40. _ -> ((J3 + 305) rem 365) + 123
  41. end,
  42. Year = (Y + Q2 * 4) - 4800,
  43. Q3 = J4 * 2141 div 65536,
  44. Day = J4 - 7834 * Q3 div 256,
  45. Month = (Q3 + 10) rem 12 + 1,
  46. {Year, Month, Day}.
  47. date2j({Y, M, D}) ->
  48. M2 = case M > 2 of
  49. true ->
  50. M + 1;
  51. false ->
  52. M + 13
  53. end,
  54. Y2 = case M > 2 of
  55. true ->
  56. Y + 4800;
  57. false ->
  58. Y + 4799
  59. end,
  60. C = Y2 div 100,
  61. J1 = Y2 * 365 - 32167,
  62. J2 = J1 + (Y2 div 4 - C + C div 4),
  63. J2 + 7834 * M2 div 256 + D.
  64. i2time(N) ->
  65. Hour = N div ?USECS_PER_HOUR,
  66. R1 = N - Hour * ?USECS_PER_HOUR,
  67. Min = R1 div ?USECS_PER_MINUTE,
  68. R2 = R1 - Min * ?USECS_PER_MINUTE,
  69. Sec = R2 div ?USECS_PER_SEC,
  70. US = R2 - Sec * ?USECS_PER_SEC,
  71. {Hour, Min, Sec + US / ?USECS_PER_SEC}.
  72. time2i({H, M, S}) ->
  73. US = trunc(round(S * ?USECS_PER_SEC)),
  74. ((H * ?MINS_PER_HOUR + M) * ?SECS_PER_MINUTE) * ?USECS_PER_SEC + US.
  75. i2timestamp(N) ->
  76. case tmodulo(N, ?USECS_PER_DAY) of
  77. {T, D} when T < 0 -> i2timestamp2(D - 1 + ?POSTGRES_EPOC_JDATE, T + ?USECS_PER_DAY);
  78. {T, D} -> i2timestamp2(D + ?POSTGRES_EPOC_JDATE, T)
  79. end.
  80. i2timestamp2(D, T) ->
  81. {j2date(D), i2time(T)}.
  82. timestamp2i({Date, Time}) ->
  83. D = date2j(Date) - ?POSTGRES_EPOC_JDATE,
  84. D * ?USECS_PER_DAY + time2i(Time).
  85. now2i({MegaSecs, Secs, MicroSecs}) ->
  86. (MegaSecs * 1000000 + Secs) * 1000000 + MicroSecs - ?POSTGRES_EPOC_USECS.
  87. tmodulo(T, U) ->
  88. case T div U of
  89. 0 -> {T, 0};
  90. Q -> {T - (Q * U), Q}
  91. end.