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).