* luci/libs/http: added inline documentation to luci.http.protocol & friends, fixed...
[project/luci.git] / libs / http / luasrc / http / protocol / date.lua
1 --[[
2
3 HTTP protocol implementation for LuCI - date handling
4 (c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13
14 ]]--
15
16 --- LuCI http protocol implementation - date helper class.
17 -- This class contains functions to parse, compare and format http dates.
18 module("luci.http.protocol.date", package.seeall)
19
20 MONTHS = {
21 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
22 "Sep", "Oct", "Nov", "Dec"
23 }
24
25 --- The "TZ" table contains lowercased timezone names associated with their
26 -- corresponding time offsets sepcified in seconds.
27 -- @class table
28 TZ = {
29 -- DST zones
30 ["brst"] = -2*3600; -- Brazil Summer Time (East Daylight)
31 ["adt"] = -3*3600; -- Atlantic Daylight
32 ["edt"] = -4*3600; -- Eastern Daylight
33 ["cdt"] = -5*3600; -- Central Daylight
34 ["mdt"] = -6*3600; -- Mountain Daylight
35 ["pdt"] = -7*3600; -- Pacific Daylight
36 ["ydt"] = -8*3600; -- Yukon Daylight
37 ["hdt"] = -9*3600; -- Hawaii Daylight
38 ["bst"] = 1*3600; -- British Summer
39 ["mest"] = 2*3600; -- Middle European Summer
40 ["sst"] = 2*3600; -- Swedish Summer
41 ["fst"] = 2*3600; -- French Summer
42 ["eest"] = 3*3600; -- Eastern European Summer
43 ["cest"] = 2*3600; -- Central European Daylight
44 ["wadt"] = 8*3600; -- West Australian Daylight
45 ["kdt"] = 10*3600; -- Korean Daylight
46 ["eadt"] = 11*3600; -- Eastern Australian Daylight
47 ["nzdt"] = 13*3600; -- New Zealand Daylight
48
49 -- zones
50 ["gmt"] = 0; -- Greenwich Mean
51 ["ut"] = 0; -- Universal (Coordinated)
52 ["utc"] = 0;
53 ["wet"] = 0; -- Western European
54 ["wat"] = -1*3600; -- West Africa
55 ["azost"] = -1*3600; -- Azores Standard Time
56 ["cvt"] = -1*3600; -- Cape Verde Time
57 ["at"] = -2*3600; -- Azores
58 ["fnt"] = -2*3600; -- Brazil Time (Extreme East - Fernando Noronha)
59 ["ndt"] = -2*3600+1800;-- Newfoundland Daylight
60 ["art"] = -3*3600; -- Argentina Time
61 ["nft"] = -3*3600+1800;-- Newfoundland
62 ["mnt"] = -4*3600; -- Brazil Time (West Standard - Manaus)
63 ["ewt"] = -4*3600; -- U.S. Eastern War Time
64 ["ast"] = -4*3600; -- Atlantic Standard
65 ["bot"] = -4*3600; -- Bolivia Time
66 ["vet"] = -4*3600; -- Venezuela Time
67 ["est"] = -5*3600; -- Eastern Standard
68 ["cot"] = -5*3600; -- Colombia Time
69 ["act"] = -5*3600; -- Brazil Time (Extreme West - Acre)
70 ["pet"] = -5*3600; -- Peru Time
71 ["cst"] = -6*3600; -- Central Standard
72 ["cest"] = 2*3600; -- Central European Summer
73 ["mst"] = -7*3600; -- Mountain Standard
74 ["pst"] = -8*3600; -- Pacific Standard
75 ["yst"] = -9*3600; -- Yukon Standard
76 ["hst"] = -10*3600; -- Hawaii Standard
77 ["cat"] = -10*3600; -- Central Alaska
78 ["ahst"] = -10*3600; -- Alaska-Hawaii Standard
79 ["taht"] = -10*3600; -- Tahiti Time
80 ["nt"] = -11*3600; -- Nome
81 ["idlw"] = -12*3600; -- International Date Line West
82 ["cet"] = 1*3600; -- Central European
83 ["mez"] = 1*3600; -- Central European (German)
84 ["met"] = 1*3600; -- Middle European
85 ["mewt"] = 1*3600; -- Middle European Winter
86 ["swt"] = 1*3600; -- Swedish Winter
87 ["set"] = 1*3600; -- Seychelles
88 ["fwt"] = 1*3600; -- French Winter
89 ["west"] = 1*3600; -- Western Europe Summer Time
90 ["eet"] = 2*3600; -- Eastern Europe; USSR Zone 1
91 ["ukr"] = 2*3600; -- Ukraine
92 ["sast"] = 2*3600; -- South Africa Standard Time
93 ["bt"] = 3*3600; -- Baghdad; USSR Zone 2
94 ["eat"] = 3*3600; -- East Africa Time
95 ["irst"] = 3*3600+1800;-- Iran Standard Time
96 ["zp4"] = 4*3600; -- USSR Zone 3
97 ["msd"] = 4*3600; -- Moscow Daylight Time
98 ["sct"] = 4*3600; -- Seychelles Time
99 ["zp5"] = 5*3600; -- USSR Zone 4
100 ["azst"] = 5*3600; -- Azerbaijan Summer Time
101 ["mvt"] = 5*3600; -- Maldives Time
102 ["uzt"] = 5*3600; -- Uzbekistan Time
103 ["ist"] = 5*3600+1800;-- Indian Standard
104 ["zp6"] = 6*3600; -- USSR Zone 5
105 ["lkt"] = 6*3600; -- Sri Lanka Time
106 ["pkst"] = 6*3600; -- Pakistan Summer Time
107 ["yekst"] = 6*3600; -- Yekaterinburg Summer Time
108 ["wast"] = 7*3600; -- West Australian Standard
109 ["ict"] = 7*3600; -- Indochina Time
110 ["wit"] = 7*3600; -- Western Indonesia Time
111 ["cct"] = 8*3600; -- China Coast; USSR Zone 7
112 ["wst"] = 8*3600; -- West Australian Standard
113 ["hkt"] = 8*3600; -- Hong Kong
114 ["bnt"] = 8*3600; -- Brunei Darussalam Time
115 ["cit"] = 8*3600; -- Central Indonesia Time
116 ["myt"] = 8*3600; -- Malaysia Time
117 ["pht"] = 8*3600; -- Philippines Time
118 ["sgt"] = 8*3600; -- Singapore Time
119 ["jst"] = 9*3600; -- Japan Standard; USSR Zone 8
120 ["kst"] = 9*3600; -- Korean Standard
121 ["east"] = 10*3600; -- Eastern Australian Standard
122 ["gst"] = 10*3600; -- Guam Standard; USSR Zone 9
123 ["nct"] = 11*3600; -- New Caledonia Time
124 ["nzt"] = 12*3600; -- New Zealand
125 ["nzst"] = 12*3600; -- New Zealand Standard
126 ["fjt"] = 12*3600; -- Fiji Time
127 ["idle"] = 12*3600; -- International Date Line East
128 }
129
130 --- Return the time offset in seconds between the UTC and given time zone.
131 -- @param tz Symbolic or numeric timezone specifier
132 -- @return Time offset to UTC in seconds
133 function tz_offset(tz)
134
135 if type(tz) == "string" then
136
137 -- check for a numeric identifier
138 local s, v = tz:match("([%+%-])([0-9]+)")
139 if s == '+' then s = 1 else s = -1 end
140 if v then v = tonumber(v) end
141
142 if s and v then
143 return s * 60 * ( math.floor( v / 100 ) * 60 + ( v % 100 ) )
144
145 -- lookup symbolic tz
146 elseif TZ[tz:lower()] then
147 return TZ[tz:lower()]
148 end
149
150 end
151
152 -- bad luck
153 return 0
154 end
155
156 --- Parse given HTTP date string and convert it to unix epoch time.
157 -- @param data String containing the date
158 -- @return Unix epoch time
159 function to_unix(date)
160
161 local wd, day, mon, yr, hr, min, sec, tz = date:match(
162 "([A-Z][a-z][a-z]), ([0-9]+) " ..
163 "([A-Z][a-z][a-z]) ([0-9]+) " ..
164 "([0-9]+):([0-9]+):([0-9]+) " ..
165 "([A-Z0-9%+%-]+)"
166 )
167
168 if day and mon and yr and hr and min and sec then
169 -- find month
170 local month = 1
171 for i = 1, 12 do
172 if MONTHS[i] == mon then
173 month = i
174 break
175 end
176 end
177
178 -- convert to epoch time
179 return tz_offset(tz) + os.time( {
180 year = yr,
181 month = month,
182 day = day,
183 hour = hr,
184 min = min,
185 sec = sec
186 } )
187 end
188
189 return 0
190 end
191
192 --- Convert the given unix epoch time to valid HTTP date string.
193 -- @param time Unix epoch time
194 -- @return String containing the formatted date
195 function to_http(time)
196 return os.date( "%a, %d %b %Y %H:%M:%S GMT", time )
197 end
198
199 --- Compare two dates which can either be unix epoch times or HTTP date strings.
200 -- @param d1 The first date or epoch time to compare
201 -- @param d2 The first date or epoch time to compare
202 -- @return -1 - if d1 is lower then d2
203 -- @return 0 - if both dates are equal
204 -- @return 1 - if d1 is higher then d2
205 function compare(d1, d2)
206
207 if d1:match("[^0-9]") then d1 = to_unix(d1) end
208 if d2:match("[^0-9]") then d2 = to_unix(d2) end
209
210 if d1 == d2 then
211 return 0
212 elseif d1 < d2 then
213 return -1
214 else
215 return 1
216 end
217 end