1%% Copyright (c) 2013-2014, 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([rfc2109/1]).
18
19%% @doc Return the date formatted according to RFC2109.
20
21-spec rfc2109(calendar:datetime()) -> binary().
22rfc2109({Date = {Y, Mo, D}, {H, Mi, S}}) ->
23	Wday = calendar:day_of_the_week(Date),
24	<<	(weekday(Wday))/binary, ", ",
25		(pad_int(D))/binary, "-",
26		(month(Mo))/binary, "-",
27		(year(Y))/binary, " ",
28		(pad_int(H))/binary, ":",
29		(pad_int(Mi))/binary, ":",
30		(pad_int(S))/binary, " GMT" >>.
31
32-ifdef(TEST).
33rfc2109_test_() ->
34	Tests = [
35		{<<"Sat, 14-May-2011 14:25:33 GMT">>, {{2011, 5, 14}, {14, 25, 33}}},
36		{<<"Sun, 01-Jan-2012 00:00:00 GMT">>, {{2012, 1,  1}, { 0,  0,  0}}}
37	],
38	[{R, fun() -> R = rfc2109(D) end} || {R, D} <- Tests].
39-endif.
40
41-ifdef(PERF).
42horse_rfc2019_20130101_000000() ->
43	horse:repeat(100000,
44		rfc2109({{2013, 1, 1}, {0, 0, 0}})
45	).
46
47horse_rfc2019_20131231_235959() ->
48	horse:repeat(100000,
49		rfc2109({{2013, 12, 31}, {23, 59, 59}})
50	).
51
52horse_rfc2019_12340506_070809() ->
53	horse:repeat(100000,
54		rfc2109({{1234, 5, 6}, {7, 8, 9}})
55	).
56-endif.
57
58%% Internal.
59
60-spec pad_int(0..59) -> <<_:16>>.
61pad_int( 0) -> <<"00">>;
62pad_int( 1) -> <<"01">>;
63pad_int( 2) -> <<"02">>;
64pad_int( 3) -> <<"03">>;
65pad_int( 4) -> <<"04">>;
66pad_int( 5) -> <<"05">>;
67pad_int( 6) -> <<"06">>;
68pad_int( 7) -> <<"07">>;
69pad_int( 8) -> <<"08">>;
70pad_int( 9) -> <<"09">>;
71pad_int(10) -> <<"10">>;
72pad_int(11) -> <<"11">>;
73pad_int(12) -> <<"12">>;
74pad_int(13) -> <<"13">>;
75pad_int(14) -> <<"14">>;
76pad_int(15) -> <<"15">>;
77pad_int(16) -> <<"16">>;
78pad_int(17) -> <<"17">>;
79pad_int(18) -> <<"18">>;
80pad_int(19) -> <<"19">>;
81pad_int(20) -> <<"20">>;
82pad_int(21) -> <<"21">>;
83pad_int(22) -> <<"22">>;
84pad_int(23) -> <<"23">>;
85pad_int(24) -> <<"24">>;
86pad_int(25) -> <<"25">>;
87pad_int(26) -> <<"26">>;
88pad_int(27) -> <<"27">>;
89pad_int(28) -> <<"28">>;
90pad_int(29) -> <<"29">>;
91pad_int(30) -> <<"30">>;
92pad_int(31) -> <<"31">>;
93pad_int(32) -> <<"32">>;
94pad_int(33) -> <<"33">>;
95pad_int(34) -> <<"34">>;
96pad_int(35) -> <<"35">>;
97pad_int(36) -> <<"36">>;
98pad_int(37) -> <<"37">>;
99pad_int(38) -> <<"38">>;
100pad_int(39) -> <<"39">>;
101pad_int(40) -> <<"40">>;
102pad_int(41) -> <<"41">>;
103pad_int(42) -> <<"42">>;
104pad_int(43) -> <<"43">>;
105pad_int(44) -> <<"44">>;
106pad_int(45) -> <<"45">>;
107pad_int(46) -> <<"46">>;
108pad_int(47) -> <<"47">>;
109pad_int(48) -> <<"48">>;
110pad_int(49) -> <<"49">>;
111pad_int(50) -> <<"50">>;
112pad_int(51) -> <<"51">>;
113pad_int(52) -> <<"52">>;
114pad_int(53) -> <<"53">>;
115pad_int(54) -> <<"54">>;
116pad_int(55) -> <<"55">>;
117pad_int(56) -> <<"56">>;
118pad_int(57) -> <<"57">>;
119pad_int(58) -> <<"58">>;
120pad_int(59) -> <<"59">>.
121
122-spec weekday(1..7) -> <<_:24>>.
123weekday(1) -> <<"Mon">>;
124weekday(2) -> <<"Tue">>;
125weekday(3) -> <<"Wed">>;
126weekday(4) -> <<"Thu">>;
127weekday(5) -> <<"Fri">>;
128weekday(6) -> <<"Sat">>;
129weekday(7) -> <<"Sun">>.
130
131-spec month(1..12) -> <<_:24>>.
132month( 1) -> <<"Jan">>;
133month( 2) -> <<"Feb">>;
134month( 3) -> <<"Mar">>;
135month( 4) -> <<"Apr">>;
136month( 5) -> <<"May">>;
137month( 6) -> <<"Jun">>;
138month( 7) -> <<"Jul">>;
139month( 8) -> <<"Aug">>;
140month( 9) -> <<"Sep">>;
141month(10) -> <<"Oct">>;
142month(11) -> <<"Nov">>;
143month(12) -> <<"Dec">>.
144
145-spec year(pos_integer()) -> <<_:32>>.
146year(1970) -> <<"1970">>;
147year(1971) -> <<"1971">>;
148year(1972) -> <<"1972">>;
149year(1973) -> <<"1973">>;
150year(1974) -> <<"1974">>;
151year(1975) -> <<"1975">>;
152year(1976) -> <<"1976">>;
153year(1977) -> <<"1977">>;
154year(1978) -> <<"1978">>;
155year(1979) -> <<"1979">>;
156year(1980) -> <<"1980">>;
157year(1981) -> <<"1981">>;
158year(1982) -> <<"1982">>;
159year(1983) -> <<"1983">>;
160year(1984) -> <<"1984">>;
161year(1985) -> <<"1985">>;
162year(1986) -> <<"1986">>;
163year(1987) -> <<"1987">>;
164year(1988) -> <<"1988">>;
165year(1989) -> <<"1989">>;
166year(1990) -> <<"1990">>;
167year(1991) -> <<"1991">>;
168year(1992) -> <<"1992">>;
169year(1993) -> <<"1993">>;
170year(1994) -> <<"1994">>;
171year(1995) -> <<"1995">>;
172year(1996) -> <<"1996">>;
173year(1997) -> <<"1997">>;
174year(1998) -> <<"1998">>;
175year(1999) -> <<"1999">>;
176year(2000) -> <<"2000">>;
177year(2001) -> <<"2001">>;
178year(2002) -> <<"2002">>;
179year(2003) -> <<"2003">>;
180year(2004) -> <<"2004">>;
181year(2005) -> <<"2005">>;
182year(2006) -> <<"2006">>;
183year(2007) -> <<"2007">>;
184year(2008) -> <<"2008">>;
185year(2009) -> <<"2009">>;
186year(2010) -> <<"2010">>;
187year(2011) -> <<"2011">>;
188year(2012) -> <<"2012">>;
189year(2013) -> <<"2013">>;
190year(2014) -> <<"2014">>;
191year(2015) -> <<"2015">>;
192year(2016) -> <<"2016">>;
193year(2017) -> <<"2017">>;
194year(2018) -> <<"2018">>;
195year(2019) -> <<"2019">>;
196year(2020) -> <<"2020">>;
197year(2021) -> <<"2021">>;
198year(2022) -> <<"2022">>;
199year(2023) -> <<"2023">>;
200year(2024) -> <<"2024">>;
201year(2025) -> <<"2025">>;
202year(2026) -> <<"2026">>;
203year(2027) -> <<"2027">>;
204year(2028) -> <<"2028">>;
205year(2029) -> <<"2029">>;
206year(Year) -> list_to_binary(integer_to_list(Year)).
207