@@ -137,6 +137,86 @@ local encoding = mime_charset / string.lower
137137local encoded_text = (printable_character - S " ?" )^ 1
138138local encoded_word = P " =?" * charset * P " ?" * encoding * P " ?" * C (encoded_text ) * P " ?="
139139
140+ local date_time do -- RFC 5322 Section 3.3
141+ local _2DIGIT = DIGIT * DIGIT
142+ local _4DIGIT = _2DIGIT * _2DIGIT
143+
144+ local function tonumber_10 (s )
145+ return tonumber (s , 10 )
146+ end
147+
148+ -- captured value follow's Lua's os.date yday convention
149+ local day_name = (P " Mon" + P " Tue" + P " Wed" + P " Thu" + P " Fri" + P " Sat" + P " Sun" ) / {
150+ Mon = 2 ;
151+ Tue = 3 ;
152+ Wed = 4 ;
153+ Thu = 5 ;
154+ Fri = 6 ;
155+ Sat = 7 ;
156+ Sun = 1 ;
157+ }
158+ local obs_day_of_week = CFWS ^- 1 * day_name * CFWS ^- 1
159+ local day_of_week = obs_day_of_week
160+ local obs_day = CFWS ^- 1 * (_2DIGIT ^ 1 / tonumber_10 ) * CFWS ^- 1
161+ local day = obs_day / 1
162+ local month = (P " Jan" + P " Feb" + P " Mar" + P " Apr" + P " May" + P " Jun" + P " Jul" + P " Aug" + P " Sep" + P " Oct" + P " Nov" + P " Dec" ) / {
163+ Jan = 1 ;
164+ Feb = 2 ;
165+ Mar = 3 ;
166+ Apr = 4 ;
167+ May = 5 ;
168+ Jun = 6 ;
169+ Jul = 7 ;
170+ Aug = 8 ;
171+ Sep = 9 ;
172+ Oct = 10 ;
173+ Nov = 11 ;
174+ Dec = 12 ;
175+ }
176+ local obs_year = CFWS ^- 1 * DIGIT ^ 2 * CFWS ^- 1 / function (y )
177+ local r = tonumber_10 (y )
178+
179+ -- If a two digit year is encountered whose value is between 00 and 49,
180+ -- the year is interpreted by adding 2000, ending up with a value between 2000 and 2049.
181+ if # y == 2 and r < 50 then
182+ return r + 2000
183+ end
184+
185+ -- If a two digit year is encountered with a value between 50 and 99,
186+ -- or any three digit year is encountered, the year is interpreted by adding 1900.
187+ if # y <= 3 then
188+ return r + 1900
189+ end
190+
191+ return r
192+ end
193+ local year = obs_year / 1
194+ local date = Cg (day , " day" ) * Cg (month , " month" ) * Cg (year , " year" )
195+
196+ local obs_hour = CFWS ^- 1 * (_2DIGIT / tonumber_10 ) * CFWS ^- 1
197+ local hour = obs_hour / 1
198+ local obs_minute = CFWS ^- 1 * (_2DIGIT / tonumber_10 ) * CFWS ^- 1
199+ local minute = obs_minute / 1
200+ local obs_second = CFWS ^- 1 * (_2DIGIT / tonumber_10 ) * CFWS ^- 1
201+ local second = obs_second / 1
202+ local time_of_day = Cg (hour , " hour" ) * P " :" * Cg (minute , " min" ) * (P " :" * Cg (second , " sec" ))^- 1
203+ local obs_zone = (P " UT" + P " GMT" ) / " +0000"
204+ + P " EST" / " -0500"
205+ + P " EDT" / " -0400"
206+ + P " CST" / " -0600"
207+ + P " CDT" / " -0500"
208+ + P " MST" / " -0700"
209+ + P " MDT" / " -0600"
210+ + P " PST" / " -0800"
211+ + P " PDT" / " -0700"
212+ + R (" \65\73 " , " \75\90 " , " \97\105 " , " \107\122 " ) / " -0000"
213+ -- the FWS isn't optional in RFC5322
214+ local zone = FWS ^- 1 / 0 * C (S " +-" * _4DIGIT ) + obs_zone
215+ local time = time_of_day * Cg (zone , " zone" )
216+
217+ date_time = (Cg (day_of_week , " wday" ) * P " ," )^- 1 * date * time * CFWS ^- 1
218+ end
219+
140220return {
141221 obs_NO_WS_CTL = obs_NO_WS_CTL ;
142222 obs_qp = obs_qp ;
@@ -196,6 +276,7 @@ return {
196276 encoding = encoding ;
197277 encoded_text = encoded_text ;
198278 encoded_word = encoded_word ;
279+ date_time = date_time ;
199280
200281 -- Handy alias
201282 email = addr_spec ;
0 commit comments