zf

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

cow_date.erl (17865B)


      1 %% Copyright (c) 2013-2018, Loïc Hoguin <essen@ninenines.eu>
      2 %%
      3 %% Permission to use, copy, modify, and/or distribute this software for any
      4 %% purpose with or without fee is hereby granted, provided that the above
      5 %% copyright notice and this permission notice appear in all copies.
      6 %%
      7 %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8 %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9 %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     10 %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11 %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     12 %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     13 %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     14 
     15 -module(cow_date).
     16 
     17 -export([parse_date/1]).
     18 -export([rfc1123/1]).
     19 -export([rfc2109/1]).
     20 -export([rfc7231/1]).
     21 
     22 -ifdef(TEST).
     23 -include_lib("proper/include/proper.hrl").
     24 -endif.
     25 
     26 %% @doc Parse the HTTP date (IMF-fixdate, rfc850, asctime).
     27 
     28 -define(DIGITS(A, B), ((A - $0) * 10 + (B - $0))).
     29 -define(DIGITS(A, B, C, D), ((A - $0) * 1000 + (B - $0) * 100 + (C - $0) * 10 + (D - $0))).
     30 
     31 -spec parse_date(binary()) -> calendar:datetime().
     32 parse_date(DateBin) ->
     33 	Date = {{_, _, D}, {H, M, S}} = http_date(DateBin),
     34 	true = D >= 0 andalso D =< 31,
     35 	true = H >= 0 andalso H =< 23,
     36 	true = M >= 0 andalso M =< 59,
     37 	true = S >= 0 andalso S =< 60, %% Leap second.
     38 	Date.
     39 
     40 http_date(<<"Mon, ", D1, D2, " ", R/bits >>) -> fixdate(R, ?DIGITS(D1, D2));
     41 http_date(<<"Tue, ", D1, D2, " ", R/bits >>) -> fixdate(R, ?DIGITS(D1, D2));
     42 http_date(<<"Wed, ", D1, D2, " ", R/bits >>) -> fixdate(R, ?DIGITS(D1, D2));
     43 http_date(<<"Thu, ", D1, D2, " ", R/bits >>) -> fixdate(R, ?DIGITS(D1, D2));
     44 http_date(<<"Fri, ", D1, D2, " ", R/bits >>) -> fixdate(R, ?DIGITS(D1, D2));
     45 http_date(<<"Sat, ", D1, D2, " ", R/bits >>) -> fixdate(R, ?DIGITS(D1, D2));
     46 http_date(<<"Sun, ", D1, D2, " ", R/bits >>) -> fixdate(R, ?DIGITS(D1, D2));
     47 http_date(<<"Monday, ", D1, D2, "-", R/bits >>) -> rfc850_date(R, ?DIGITS(D1, D2));
     48 http_date(<<"Tuesday, ", D1, D2, "-", R/bits >>) -> rfc850_date(R, ?DIGITS(D1, D2));
     49 http_date(<<"Wednesday, ", D1, D2, "-", R/bits >>) -> rfc850_date(R, ?DIGITS(D1, D2));
     50 http_date(<<"Thursday, ", D1, D2, "-", R/bits >>) -> rfc850_date(R, ?DIGITS(D1, D2));
     51 http_date(<<"Friday, ", D1, D2, "-", R/bits >>) -> rfc850_date(R, ?DIGITS(D1, D2));
     52 http_date(<<"Saturday, ", D1, D2, "-", R/bits >>) -> rfc850_date(R, ?DIGITS(D1, D2));
     53 http_date(<<"Sunday, ", D1, D2, "-", R/bits >>) -> rfc850_date(R, ?DIGITS(D1, D2));
     54 http_date(<<"Mon ", R/bits >>) -> asctime_date(R);
     55 http_date(<<"Tue ", R/bits >>) -> asctime_date(R);
     56 http_date(<<"Wed ", R/bits >>) -> asctime_date(R);
     57 http_date(<<"Thu ", R/bits >>) -> asctime_date(R);
     58 http_date(<<"Fri ", R/bits >>) -> asctime_date(R);
     59 http_date(<<"Sat ", R/bits >>) -> asctime_date(R);
     60 http_date(<<"Sun ", R/bits >>) -> asctime_date(R).
     61 
     62 fixdate(<<"Jan ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     63 	{{?DIGITS(Y1, Y2, Y3, Y4), 1, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     64 fixdate(<<"Feb ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     65 	{{?DIGITS(Y1, Y2, Y3, Y4), 2, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     66 fixdate(<<"Mar ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     67 	{{?DIGITS(Y1, Y2, Y3, Y4), 3, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     68 fixdate(<<"Apr ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     69 	{{?DIGITS(Y1, Y2, Y3, Y4), 4, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     70 fixdate(<<"May ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     71 	{{?DIGITS(Y1, Y2, Y3, Y4), 5, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     72 fixdate(<<"Jun ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     73 	{{?DIGITS(Y1, Y2, Y3, Y4), 6, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     74 fixdate(<<"Jul ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     75 	{{?DIGITS(Y1, Y2, Y3, Y4), 7, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     76 fixdate(<<"Aug ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     77 	{{?DIGITS(Y1, Y2, Y3, Y4), 8, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     78 fixdate(<<"Sep ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     79 	{{?DIGITS(Y1, Y2, Y3, Y4), 9, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     80 fixdate(<<"Oct ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     81 	{{?DIGITS(Y1, Y2, Y3, Y4), 10, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     82 fixdate(<<"Nov ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     83 	{{?DIGITS(Y1, Y2, Y3, Y4), 11, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     84 fixdate(<<"Dec ", Y1, Y2, Y3, Y4, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     85 	{{?DIGITS(Y1, Y2, Y3, Y4), 12, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}}.
     86 
     87 rfc850_date(<<"Jan-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     88 	{{rfc850_year(?DIGITS(Y1, Y2)), 1, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     89 rfc850_date(<<"Feb-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     90 	{{rfc850_year(?DIGITS(Y1, Y2)), 2, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     91 rfc850_date(<<"Mar-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     92 	{{rfc850_year(?DIGITS(Y1, Y2)), 3, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     93 rfc850_date(<<"Apr-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     94 	{{rfc850_year(?DIGITS(Y1, Y2)), 4, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     95 rfc850_date(<<"May-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     96 	{{rfc850_year(?DIGITS(Y1, Y2)), 5, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     97 rfc850_date(<<"Jun-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
     98 	{{rfc850_year(?DIGITS(Y1, Y2)), 6, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
     99 rfc850_date(<<"Jul-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
    100 	{{rfc850_year(?DIGITS(Y1, Y2)), 7, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    101 rfc850_date(<<"Aug-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
    102 	{{rfc850_year(?DIGITS(Y1, Y2)), 8, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    103 rfc850_date(<<"Sep-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
    104 	{{rfc850_year(?DIGITS(Y1, Y2)), 9, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    105 rfc850_date(<<"Oct-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
    106 	{{rfc850_year(?DIGITS(Y1, Y2)), 10, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    107 rfc850_date(<<"Nov-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
    108 	{{rfc850_year(?DIGITS(Y1, Y2)), 11, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    109 rfc850_date(<<"Dec-", Y1, Y2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " GMT">>, Day) ->
    110 	{{rfc850_year(?DIGITS(Y1, Y2)), 12, Day}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}}.
    111 
    112 rfc850_year(Y) when Y > 50 -> Y + 1900;
    113 rfc850_year(Y) -> Y + 2000.
    114 
    115 asctime_date(<<"Jan ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    116 	{{?DIGITS(Y1, Y2, Y3, Y4), 1, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    117 asctime_date(<<"Feb ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    118 	{{?DIGITS(Y1, Y2, Y3, Y4), 2, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    119 asctime_date(<<"Mar ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    120 	{{?DIGITS(Y1, Y2, Y3, Y4), 3, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    121 asctime_date(<<"Apr ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    122 	{{?DIGITS(Y1, Y2, Y3, Y4), 4, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    123 asctime_date(<<"May ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    124 	{{?DIGITS(Y1, Y2, Y3, Y4), 5, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    125 asctime_date(<<"Jun ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    126 	{{?DIGITS(Y1, Y2, Y3, Y4), 6, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    127 asctime_date(<<"Jul ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    128 	{{?DIGITS(Y1, Y2, Y3, Y4), 7, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    129 asctime_date(<<"Aug ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    130 	{{?DIGITS(Y1, Y2, Y3, Y4), 8, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    131 asctime_date(<<"Sep ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    132 	{{?DIGITS(Y1, Y2, Y3, Y4), 9, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    133 asctime_date(<<"Oct ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    134 	{{?DIGITS(Y1, Y2, Y3, Y4), 10, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    135 asctime_date(<<"Nov ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    136 	{{?DIGITS(Y1, Y2, Y3, Y4), 11, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}};
    137 asctime_date(<<"Dec ", D1, D2, " ", H1, H2, ":", M1, M2, ":", S1, S2, " ", Y1, Y2, Y3, Y4 >>) ->
    138 	{{?DIGITS(Y1, Y2, Y3, Y4), 12, asctime_day(D1, D2)}, {?DIGITS(H1, H2), ?DIGITS(M1, M2), ?DIGITS(S1, S2)}}.
    139 
    140 asctime_day($\s, D2) -> (D2 - $0);
    141 asctime_day(D1, D2) -> (D1 - $0) * 10 + (D2 - $0).
    142 
    143 -ifdef(TEST).
    144 day_name() -> oneof(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]).
    145 day_name_l() -> oneof(["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]).
    146 year() -> integer(1951, 2050).
    147 month() -> integer(1, 12).
    148 day() -> integer(1, 31).
    149 hour() -> integer(0, 23).
    150 minute() -> integer(0, 59).
    151 second() -> integer(0, 60).
    152 
    153 fixdate_gen() ->
    154 	?LET({DayName, Y, Mo, D, H, Mi, S},
    155 		{day_name(), year(), month(), day(), hour(), minute(), second()},
    156 		{{{Y, Mo, D}, {H, Mi, S}},
    157 			list_to_binary([DayName, ", ", pad_int(D), " ", month(Mo), " ", integer_to_binary(Y),
    158 			" ", pad_int(H), ":", pad_int(Mi), ":", pad_int(S), " GMT"])}).
    159 
    160 rfc850_gen() ->
    161 	?LET({DayName, Y, Mo, D, H, Mi, S},
    162 		{day_name_l(), year(), month(), day(), hour(), minute(), second()},
    163 		{{{Y, Mo, D}, {H, Mi, S}},
    164 			list_to_binary([DayName, ", ", pad_int(D), "-", month(Mo), "-", pad_int(Y rem 100),
    165 			" ", pad_int(H), ":", pad_int(Mi), ":", pad_int(S), " GMT"])}).
    166 
    167 asctime_gen() ->
    168 	?LET({DayName, Y, Mo, D, H, Mi, S},
    169 		{day_name(), year(), month(), day(), hour(), minute(), second()},
    170 		{{{Y, Mo, D}, {H, Mi, S}},
    171 			list_to_binary([DayName, " ", month(Mo), " ",
    172 			if D < 10 -> << $\s, (D + $0) >>; true -> integer_to_binary(D) end,
    173 			" ", pad_int(H), ":", pad_int(Mi), ":", pad_int(S), " ", integer_to_binary(Y)])}).
    174 
    175 prop_http_date() ->
    176 	?FORALL({Date, DateBin},
    177 		oneof([fixdate_gen(), rfc850_gen(), asctime_gen()]),
    178 		Date =:= parse_date(DateBin)).
    179 
    180 http_date_test_() ->
    181 	Tests = [
    182 		{<<"Sun, 06 Nov 1994 08:49:37 GMT">>, {{1994, 11, 6}, {8, 49, 37}}},
    183 		{<<"Sunday, 06-Nov-94 08:49:37 GMT">>, {{1994, 11, 6}, {8, 49, 37}}},
    184 		{<<"Sun Nov  6 08:49:37 1994">>, {{1994, 11, 6}, {8, 49, 37}}}
    185 	],
    186 	[{V, fun() -> R = http_date(V) end} || {V, R} <- Tests].
    187 
    188 horse_http_date_fixdate() ->
    189 	horse:repeat(200000,
    190 		http_date(<<"Sun, 06 Nov 1994 08:49:37 GMT">>)
    191 	).
    192 
    193 horse_http_date_rfc850() ->
    194 	horse:repeat(200000,
    195 		http_date(<<"Sunday, 06-Nov-94 08:49:37 GMT">>)
    196 	).
    197 
    198 horse_http_date_asctime() ->
    199 	horse:repeat(200000,
    200 		http_date(<<"Sun Nov  6 08:49:37 1994">>)
    201 	).
    202 -endif.
    203 
    204 %% @doc Return the date formatted according to RFC1123.
    205 
    206 -spec rfc1123(calendar:datetime()) -> binary().
    207 rfc1123(DateTime) ->
    208 	rfc7231(DateTime).
    209 
    210 %% @doc Return the date formatted according to RFC2109.
    211 
    212 -spec rfc2109(calendar:datetime()) -> binary().
    213 rfc2109({Date = {Y, Mo, D}, {H, Mi, S}}) ->
    214 	Wday = calendar:day_of_the_week(Date),
    215 	<<	(weekday(Wday))/binary, ", ",
    216 		(pad_int(D))/binary, "-",
    217 		(month(Mo))/binary, "-",
    218 		(year(Y))/binary, " ",
    219 		(pad_int(H))/binary, ":",
    220 		(pad_int(Mi))/binary, ":",
    221 		(pad_int(S))/binary, " GMT" >>.
    222 
    223 -ifdef(TEST).
    224 rfc2109_test_() ->
    225 	Tests = [
    226 		{<<"Sat, 14-May-2011 14:25:33 GMT">>, {{2011, 5, 14}, {14, 25, 33}}},
    227 		{<<"Sun, 01-Jan-2012 00:00:00 GMT">>, {{2012, 1,  1}, { 0,  0,  0}}}
    228 	],
    229 	[{R, fun() -> R = rfc2109(D) end} || {R, D} <- Tests].
    230 
    231 horse_rfc2109_20130101_000000() ->
    232 	horse:repeat(100000,
    233 		rfc2109({{2013, 1, 1}, {0, 0, 0}})
    234 	).
    235 
    236 horse_rfc2109_20131231_235959() ->
    237 	horse:repeat(100000,
    238 		rfc2109({{2013, 12, 31}, {23, 59, 59}})
    239 	).
    240 
    241 horse_rfc2109_12340506_070809() ->
    242 	horse:repeat(100000,
    243 		rfc2109({{1234, 5, 6}, {7, 8, 9}})
    244 	).
    245 -endif.
    246 
    247 %% @doc Return the date formatted according to RFC7231.
    248 
    249 -spec rfc7231(calendar:datetime()) -> binary().
    250 rfc7231({Date = {Y, Mo, D}, {H, Mi, S}}) ->
    251 	Wday = calendar:day_of_the_week(Date),
    252 	<<	(weekday(Wday))/binary, ", ",
    253 		(pad_int(D))/binary, " ",
    254 		(month(Mo))/binary, " ",
    255 		(year(Y))/binary, " ",
    256 		(pad_int(H))/binary, ":",
    257 		(pad_int(Mi))/binary, ":",
    258 		(pad_int(S))/binary, " GMT" >>.
    259 
    260 -ifdef(TEST).
    261 rfc7231_test_() ->
    262 	Tests = [
    263 		{<<"Sat, 14 May 2011 14:25:33 GMT">>, {{2011, 5, 14}, {14, 25, 33}}},
    264 		{<<"Sun, 01 Jan 2012 00:00:00 GMT">>, {{2012, 1,  1}, { 0,  0,  0}}}
    265 	],
    266 	[{R, fun() -> R = rfc7231(D) end} || {R, D} <- Tests].
    267 
    268 horse_rfc7231_20130101_000000() ->
    269 	horse:repeat(100000,
    270 		rfc7231({{2013, 1, 1}, {0, 0, 0}})
    271 	).
    272 
    273 horse_rfc7231_20131231_235959() ->
    274 	horse:repeat(100000,
    275 		rfc7231({{2013, 12, 31}, {23, 59, 59}})
    276 	).
    277 
    278 horse_rfc7231_12340506_070809() ->
    279 	horse:repeat(100000,
    280 		rfc7231({{1234, 5, 6}, {7, 8, 9}})
    281 	).
    282 -endif.
    283 
    284 %% Internal.
    285 
    286 -spec pad_int(0..59) -> <<_:16>>.
    287 pad_int( 0) -> <<"00">>;
    288 pad_int( 1) -> <<"01">>;
    289 pad_int( 2) -> <<"02">>;
    290 pad_int( 3) -> <<"03">>;
    291 pad_int( 4) -> <<"04">>;
    292 pad_int( 5) -> <<"05">>;
    293 pad_int( 6) -> <<"06">>;
    294 pad_int( 7) -> <<"07">>;
    295 pad_int( 8) -> <<"08">>;
    296 pad_int( 9) -> <<"09">>;
    297 pad_int(10) -> <<"10">>;
    298 pad_int(11) -> <<"11">>;
    299 pad_int(12) -> <<"12">>;
    300 pad_int(13) -> <<"13">>;
    301 pad_int(14) -> <<"14">>;
    302 pad_int(15) -> <<"15">>;
    303 pad_int(16) -> <<"16">>;
    304 pad_int(17) -> <<"17">>;
    305 pad_int(18) -> <<"18">>;
    306 pad_int(19) -> <<"19">>;
    307 pad_int(20) -> <<"20">>;
    308 pad_int(21) -> <<"21">>;
    309 pad_int(22) -> <<"22">>;
    310 pad_int(23) -> <<"23">>;
    311 pad_int(24) -> <<"24">>;
    312 pad_int(25) -> <<"25">>;
    313 pad_int(26) -> <<"26">>;
    314 pad_int(27) -> <<"27">>;
    315 pad_int(28) -> <<"28">>;
    316 pad_int(29) -> <<"29">>;
    317 pad_int(30) -> <<"30">>;
    318 pad_int(31) -> <<"31">>;
    319 pad_int(32) -> <<"32">>;
    320 pad_int(33) -> <<"33">>;
    321 pad_int(34) -> <<"34">>;
    322 pad_int(35) -> <<"35">>;
    323 pad_int(36) -> <<"36">>;
    324 pad_int(37) -> <<"37">>;
    325 pad_int(38) -> <<"38">>;
    326 pad_int(39) -> <<"39">>;
    327 pad_int(40) -> <<"40">>;
    328 pad_int(41) -> <<"41">>;
    329 pad_int(42) -> <<"42">>;
    330 pad_int(43) -> <<"43">>;
    331 pad_int(44) -> <<"44">>;
    332 pad_int(45) -> <<"45">>;
    333 pad_int(46) -> <<"46">>;
    334 pad_int(47) -> <<"47">>;
    335 pad_int(48) -> <<"48">>;
    336 pad_int(49) -> <<"49">>;
    337 pad_int(50) -> <<"50">>;
    338 pad_int(51) -> <<"51">>;
    339 pad_int(52) -> <<"52">>;
    340 pad_int(53) -> <<"53">>;
    341 pad_int(54) -> <<"54">>;
    342 pad_int(55) -> <<"55">>;
    343 pad_int(56) -> <<"56">>;
    344 pad_int(57) -> <<"57">>;
    345 pad_int(58) -> <<"58">>;
    346 pad_int(59) -> <<"59">>;
    347 pad_int(60) -> <<"60">>;
    348 pad_int(Int) -> integer_to_binary(Int).
    349 
    350 -spec weekday(1..7) -> <<_:24>>.
    351 weekday(1) -> <<"Mon">>;
    352 weekday(2) -> <<"Tue">>;
    353 weekday(3) -> <<"Wed">>;
    354 weekday(4) -> <<"Thu">>;
    355 weekday(5) -> <<"Fri">>;
    356 weekday(6) -> <<"Sat">>;
    357 weekday(7) -> <<"Sun">>.
    358 
    359 -spec month(1..12) -> <<_:24>>.
    360 month( 1) -> <<"Jan">>;
    361 month( 2) -> <<"Feb">>;
    362 month( 3) -> <<"Mar">>;
    363 month( 4) -> <<"Apr">>;
    364 month( 5) -> <<"May">>;
    365 month( 6) -> <<"Jun">>;
    366 month( 7) -> <<"Jul">>;
    367 month( 8) -> <<"Aug">>;
    368 month( 9) -> <<"Sep">>;
    369 month(10) -> <<"Oct">>;
    370 month(11) -> <<"Nov">>;
    371 month(12) -> <<"Dec">>.
    372 
    373 -spec year(pos_integer()) -> <<_:32>>.
    374 year(1970) -> <<"1970">>;
    375 year(1971) -> <<"1971">>;
    376 year(1972) -> <<"1972">>;
    377 year(1973) -> <<"1973">>;
    378 year(1974) -> <<"1974">>;
    379 year(1975) -> <<"1975">>;
    380 year(1976) -> <<"1976">>;
    381 year(1977) -> <<"1977">>;
    382 year(1978) -> <<"1978">>;
    383 year(1979) -> <<"1979">>;
    384 year(1980) -> <<"1980">>;
    385 year(1981) -> <<"1981">>;
    386 year(1982) -> <<"1982">>;
    387 year(1983) -> <<"1983">>;
    388 year(1984) -> <<"1984">>;
    389 year(1985) -> <<"1985">>;
    390 year(1986) -> <<"1986">>;
    391 year(1987) -> <<"1987">>;
    392 year(1988) -> <<"1988">>;
    393 year(1989) -> <<"1989">>;
    394 year(1990) -> <<"1990">>;
    395 year(1991) -> <<"1991">>;
    396 year(1992) -> <<"1992">>;
    397 year(1993) -> <<"1993">>;
    398 year(1994) -> <<"1994">>;
    399 year(1995) -> <<"1995">>;
    400 year(1996) -> <<"1996">>;
    401 year(1997) -> <<"1997">>;
    402 year(1998) -> <<"1998">>;
    403 year(1999) -> <<"1999">>;
    404 year(2000) -> <<"2000">>;
    405 year(2001) -> <<"2001">>;
    406 year(2002) -> <<"2002">>;
    407 year(2003) -> <<"2003">>;
    408 year(2004) -> <<"2004">>;
    409 year(2005) -> <<"2005">>;
    410 year(2006) -> <<"2006">>;
    411 year(2007) -> <<"2007">>;
    412 year(2008) -> <<"2008">>;
    413 year(2009) -> <<"2009">>;
    414 year(2010) -> <<"2010">>;
    415 year(2011) -> <<"2011">>;
    416 year(2012) -> <<"2012">>;
    417 year(2013) -> <<"2013">>;
    418 year(2014) -> <<"2014">>;
    419 year(2015) -> <<"2015">>;
    420 year(2016) -> <<"2016">>;
    421 year(2017) -> <<"2017">>;
    422 year(2018) -> <<"2018">>;
    423 year(2019) -> <<"2019">>;
    424 year(2020) -> <<"2020">>;
    425 year(2021) -> <<"2021">>;
    426 year(2022) -> <<"2022">>;
    427 year(2023) -> <<"2023">>;
    428 year(2024) -> <<"2024">>;
    429 year(2025) -> <<"2025">>;
    430 year(2026) -> <<"2026">>;
    431 year(2027) -> <<"2027">>;
    432 year(2028) -> <<"2028">>;
    433 year(2029) -> <<"2029">>;
    434 year(Year) -> integer_to_binary(Year).