* 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