2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
18 #define TRACE_PARSEDATE 0
20 # define TRACE(x) printf x ;
26 /* The date format is as follows:
36 * p meridian (i.e. am/pm)
37 * T time unit: last hour, next tuesday, today, ...
41 * Any of ",.:" is allowed and will be expected in the input string as is.
42 * You can enclose a single field with "[]" to mark it as being optional.
43 * A space stands for white space.
44 * No other character is allowed.
47 static const char * const kFormatsTable
[] = {
48 "[A][,] B d[,] H:M:S [p] Y[,] [Z]",
49 "[A][,] B d[,] [Y][,] H:M:S [p] [Z]",
50 "[A][,] B d[,] [Y][,] H:M [p][,] [Z]",
51 "[A][,] B d[,] [Y][,] H [p][,] [Z]",
52 "[A][,] B d[,] H:M [p][,] [Y] [Z]",
53 "[A][,] d B[,] [Y][,] H:M [p][,] [Z]",
54 "[A][,] d B[,] [Y][,] H:M:S [p][,] [Z]",
55 "[A][,] d B[,] H:M:S [Y][,] [p][,] [Z]",
56 "[A][,] d B[,] H:M [Y][,] [p][,] [Z]",
57 "d.m.y H:M:S [p] [Z]",
60 "[A][,] m-d-y[,] [H][:][M] [p]",
61 "[A][,] m-d[,] H:M [p]",
69 "[A][,] B d[,] H:M:S [p] [Z] [Y]",
70 "[A][,] B d[,] H:M [p] [Z] [Y]",
71 "[A][,] d B [,] H:M:S [p] [Z] [Y]",
72 "[A][,] d B [,] H:M [p] [Z] [Y]",
73 "[A][,] d-B-Y H:M:S [p] [Z]",
74 "[A][,] d-B-Y H:M [p] [Z]",
78 "y-m-d H:M:S [p] [Z]",
91 "B d[,][Y] H[p][,] [Z]",
94 "d B [,][Y] H [p] [Z]",
97 "B d [,] H:M [p][,] [Y]",
98 "B d [,] H [p][,] [Y]",
111 static const char* const* sFormatsTable
= kFormatsTable
;
138 #define FLAG_RELATIVE 1
139 #define FLAG_NOT_MODIFIABLE 2
141 #define FLAG_NEXT_LAST_THIS 8
142 #define FLAG_PLUS_MINUS 16
143 #define FLAG_HAS_DASH 32
159 enum value_modifier
{
163 MODIFY_THIS
= MODIFY_NONE
,
168 struct known_identifier
{
170 const char *alternate_string
;
177 static const known_identifier kIdentifiers
[] = {
178 {"today", NULL
, TYPE_UNIT
, FLAG_RELATIVE
| FLAG_NOT_MODIFIABLE
,
180 {"tomorrow", NULL
, TYPE_UNIT
, FLAG_RELATIVE
| FLAG_NOT_MODIFIABLE
,
182 {"yesterday", NULL
, TYPE_UNIT
, FLAG_RELATIVE
| FLAG_NOT_MODIFIABLE
,
184 {"now", NULL
, TYPE_UNIT
,
185 FLAG_RELATIVE
| FLAG_NOT_MODIFIABLE
| FLAG_NOW
, 0},
187 {"this", NULL
, TYPE_MODIFIER
, FLAG_NEXT_LAST_THIS
, UNIT_NONE
,
189 {"next", NULL
, TYPE_MODIFIER
, FLAG_NEXT_LAST_THIS
, UNIT_NONE
,
191 {"last", NULL
, TYPE_MODIFIER
, FLAG_NEXT_LAST_THIS
, UNIT_NONE
,
194 {"years", "year", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_YEAR
, 1},
195 {"months", "month",TYPE_UNIT
, FLAG_RELATIVE
, UNIT_MONTH
, 1},
196 {"weeks", "week", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_DAY
, 7},
197 {"days", "day", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_DAY
, 1},
198 {"hour", NULL
, TYPE_UNIT
, FLAG_RELATIVE
, UNIT_SECOND
, 1 * 60 * 60},
199 {"hours", "hrs", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_SECOND
, 1 * 60 * 60},
200 {"second", "sec", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_SECOND
, 1},
201 {"seconds", "secs", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_SECOND
, 1},
202 {"minute", "min", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_SECOND
, 60},
203 {"minutes", "mins", TYPE_UNIT
, FLAG_RELATIVE
, UNIT_SECOND
, 60},
205 {"am", NULL
, TYPE_MERIDIAN
, FLAG_NOT_MODIFIABLE
, UNIT_SECOND
, 0},
206 {"pm", NULL
, TYPE_MERIDIAN
, FLAG_NOT_MODIFIABLE
, UNIT_SECOND
,
209 {"sunday", "sun", TYPE_WEEKDAY
, FLAG_NONE
, UNIT_DAY
, 0},
210 {"monday", "mon", TYPE_WEEKDAY
, FLAG_NONE
, UNIT_DAY
, 1},
211 {"tuesday", "tue", TYPE_WEEKDAY
, FLAG_NONE
, UNIT_DAY
, 2},
212 {"wednesday", "wed", TYPE_WEEKDAY
, FLAG_NONE
, UNIT_DAY
, 3},
213 {"thursday", "thu", TYPE_WEEKDAY
, FLAG_NONE
, UNIT_DAY
, 4},
214 {"friday", "fri", TYPE_WEEKDAY
, FLAG_NONE
, UNIT_DAY
, 5},
215 {"saturday", "sat", TYPE_WEEKDAY
, FLAG_NONE
, UNIT_DAY
, 6},
217 {"january", "jan", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 1},
218 {"february", "feb", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 2},
219 {"march", "mar", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 3},
220 {"april", "apr", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 4},
221 {"may", "may", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 5},
222 {"june", "jun", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 6},
223 {"july", "jul", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 7},
224 {"august", "aug", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 8},
225 {"september", "sep", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 9},
226 {"october", "oct", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 10},
227 {"november", "nov", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 11},
228 {"december", "dec", TYPE_MONTH
, FLAG_NONE
, UNIT_MONTH
, 12},
230 {"GMT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 0},
231 {"UTC", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 0},
232 // the following list has been generated from info found at
233 // http://www.timegenie.com/timezones
234 {"ACDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1050 * 36},
235 {"ACIT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
236 {"ACST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 950 * 36},
237 {"ACT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -500 * 36},
238 {"ACWST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 875 * 36},
239 {"ADT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
240 {"AEDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
241 {"AEST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
242 {"AFT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 450 * 36},
243 {"AKDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -800 * 36},
244 {"AKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -900 * 36},
245 {"AMDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
246 {"AMST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
247 {"ANAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1300 * 36},
248 {"ANAT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
249 {"APO", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 825 * 36},
250 {"ARDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -200 * 36},
251 {"ART", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
252 {"AST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
253 {"AWST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
254 {"AZODT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 0 * 36},
255 {"AZOST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -100 * 36},
256 {"AZST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
257 {"AZT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
258 {"BIT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -1200 * 36},
259 {"BDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
260 {"BEST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -200 * 36},
261 {"BIOT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
262 {"BNT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
263 {"BOT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
264 {"BRST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -200 * 36},
265 {"BRT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
266 {"BST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 100 * 36},
267 {"BTT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
268 {"BWDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
269 {"BWST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
270 {"CAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
271 {"CAT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 200 * 36},
272 {"CCT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 650 * 36},
273 {"CDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -500 * 36},
274 {"CEST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 200 * 36},
275 {"CET", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 100 * 36},
276 {"CGST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -200 * 36},
277 {"CGT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
278 {"CHADT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1375 * 36},
279 {"CHAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1275 * 36},
280 {"CHST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
281 {"CIST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -800 * 36},
282 {"CKT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -1000 * 36},
283 {"CLDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
284 {"CLST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
285 {"COT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -500 * 36},
286 {"CST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -600 * 36},
287 {"CVT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -100 * 36},
288 {"CXT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
289 {"DAVT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
290 {"DTAT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
291 {"EADT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -500 * 36},
292 {"EAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -600 * 36},
293 {"EAT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 300 * 36},
294 {"ECT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -500 * 36},
295 {"EDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
296 {"EEST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 300 * 36},
297 {"EET", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 200 * 36},
298 {"EGT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -100 * 36},
299 {"EGST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 0 * 36},
300 {"EKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
301 {"EST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -500 * 36},
302 {"FJT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
303 {"FKDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
304 {"FKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
305 {"GALT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -600 * 36},
306 {"GET", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
307 {"GFT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
308 {"GILT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
309 {"GIT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -900 * 36},
310 {"GST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
311 {"GYT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
312 {"HADT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -900 * 36},
313 {"HAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -1000 * 36},
314 {"HKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
315 {"HMT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
316 {"ICT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
317 {"IDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 300 * 36},
318 {"IRDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 450 * 36},
319 {"IRKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
320 {"IRKT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
321 {"IRST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 350 * 36},
322 {"IST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 200 * 36},
323 {"JFDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
324 {"JFST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
325 {"JST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
326 {"KGST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
327 {"KGT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
328 {"KRAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
329 {"KRAT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
330 {"KOST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
331 {"KOVT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
332 {"KOVST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
333 {"KST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
334 {"LHDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
335 {"LHST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1050 * 36},
336 {"LINT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1400 * 36},
337 {"LKT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
338 {"MAGST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
339 {"MAGT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
340 {"MAWT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
341 {"MBT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
342 {"MDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -600 * 36},
343 {"MIT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -950 * 36},
344 {"MHT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
345 {"MMT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 650 * 36},
346 {"MNT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
347 {"MNST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
348 {"MSD", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
349 {"MSK", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 300 * 36},
350 {"MST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -700 * 36},
351 {"MUST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
352 {"MUT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
353 {"MVT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
354 {"MYT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
355 {"NCT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
356 {"NDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -250 * 36},
357 {"NFT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1150 * 36},
358 {"NPT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 575 * 36},
359 {"NRT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
360 {"NOVST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
361 {"NOVT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
362 {"NST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -350 * 36},
363 {"NUT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -1100 * 36},
364 {"NZDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1300 * 36},
365 {"NZST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
366 {"OMSK", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
367 {"OMST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
368 {"PDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -700 * 36},
369 {"PETST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1300 * 36},
370 {"PET", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -500 * 36},
371 {"PETT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
372 {"PGT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
373 {"PHOT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1300 * 36},
374 {"PHT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
375 {"PIT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
376 {"PKT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
377 {"PKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
378 {"PMDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -200 * 36},
379 {"PMST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
380 {"PONT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
381 {"PST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -800 * 36},
382 {"PWT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
383 {"PYST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
384 {"PYT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
385 {"RET", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
386 {"ROTT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
387 {"SAMST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
388 {"SAMT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
389 {"SAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 200 * 36},
390 {"SBT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
391 {"SCDT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1300 * 36},
392 {"SCST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
393 {"SCT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 400 * 36},
394 {"SGT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
395 {"SIT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
396 {"SLT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -400 * 36},
397 {"SLST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
398 {"SRT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
399 {"SST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -1100 * 36},
400 {"SYST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 300 * 36},
401 {"SYT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 200 * 36},
402 {"TAHT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -1000 * 36},
403 {"TFT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
404 {"TJT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
405 {"TKT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -1000 * 36},
406 {"TMT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
407 {"TOT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1300 * 36},
408 {"TPT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
409 {"TRUT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
410 {"TVT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
411 {"TWT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
412 {"UYT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -300 * 36},
413 {"UYST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -200 * 36},
414 {"UZT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
415 {"VLAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
416 {"VLAT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
417 {"VOST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
418 {"VST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, -450 * 36},
419 {"VUT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1100 * 36},
420 {"WAST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 200 * 36},
421 {"WAT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 100 * 36},
422 {"WEST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 100 * 36},
423 {"WET", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 0 * 36},
424 {"WFT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1200 * 36},
425 {"WIB", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 700 * 36},
426 {"WIT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
427 {"WITA", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 800 * 36},
428 {"WKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
429 {"YAKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
430 {"YAKT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 900 * 36},
431 {"YAPT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 1000 * 36},
432 {"YEKST", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 600 * 36},
433 {"YEKT", NULL
, TYPE_TIME_ZONE
, FLAG_NONE
, UNIT_SECOND
, 500 * 36},
438 #define MAX_ELEMENTS 32
442 DateMask() : fMask(0UL) {}
444 void Set(uint8 type
) { fMask
|= Flag(type
); }
445 bool IsSet(uint8 type
) { return (fMask
& Flag(type
)) != 0; }
451 inline uint32
Flag(uint8 type
) const { return 1UL << type
; }
457 struct parsed_element
{
466 void SetCharType(uint8 fieldType
, int8 modify
= MODIFY_NONE
);
468 void Adopt(const known_identifier
& identifier
);
469 void AdoptUnit(const known_identifier
& identifier
);
470 bool IsNextLastThis();
475 parsed_element::SetCharType(uint8 fieldType
, int8 modify
)
477 base_type
= type
= fieldType
;
478 value_type
= VALUE_CHAR
;
484 parsed_element::Adopt(const known_identifier
& identifier
)
486 base_type
= type
= identifier
.type
;
487 flags
= identifier
.flags
;
488 unit
= identifier
.unit
;
490 if (identifier
.type
== TYPE_MODIFIER
)
491 modifier
= identifier
.value
;
493 value_type
= VALUE_STRING
;
494 value
= identifier
.value
;
499 parsed_element::AdoptUnit(const known_identifier
& identifier
)
501 base_type
= type
= TYPE_UNIT
;
502 flags
= identifier
.flags
;
503 unit
= identifier
.unit
;
504 value
*= identifier
.value
;
509 parsed_element::IsNextLastThis()
511 return base_type
== TYPE_MODIFIER
512 && (modifier
== MODIFY_NEXT
|| modifier
== MODIFY_LAST
513 || modifier
== MODIFY_THIS
);
524 return IsSet(TYPE_HOUR
);
528 /*! This method checks if the date mask is complete in the
529 sense that it doesn't need to have a prefilled "struct tm"
530 when its time value is computed.
533 DateMask::IsComplete()
535 // mask must be absolute, at last
536 if ((fMask
& Flag(TYPE_UNIT
)) != 0)
539 // minimal set of flags to have a complete set
540 return !(~fMask
& (Flag(TYPE_DAY
) | Flag(TYPE_MONTH
)));
548 preparseDate(const char* dateString
, parsed_element
* elements
)
550 int32 index
= 0, modify
= MODIFY_NONE
;
553 if (dateString
== NULL
)
556 memset(&elements
[0], 0, sizeof(parsed_element
));
558 for (; (c
= dateString
[0]) != '\0'; dateString
++) {
559 // we don't care about spaces
561 modify
= MODIFY_NONE
;
565 // if we're reached our maximum number of elements, bail out
566 if (index
>= MAX_ELEMENTS
)
570 elements
[index
].SetCharType(TYPE_COMMA
);
571 } else if (c
== '.') {
572 elements
[index
].SetCharType(TYPE_DOT
);
573 } else if (c
== '/') {
574 // "-" is handled differently (as a modifier)
575 elements
[index
].SetCharType(TYPE_DASH
);
576 } else if (c
== ':') {
577 elements
[index
].SetCharType(TYPE_COLON
);
578 } else if (c
== '+') {
579 modify
= MODIFY_PLUS
;
581 // this counts for the next element
583 } else if (c
== '-') {
584 modify
= MODIFY_MINUS
;
585 elements
[index
].flags
= FLAG_HAS_DASH
;
587 // this counts for the next element
589 } else if (isdigit(c
)) {
590 // fetch whole number
592 elements
[index
].type
= TYPE_UNKNOWN
;
593 elements
[index
].value_type
= VALUE_NUMERICAL
;
594 elements
[index
].value
= atoll(dateString
);
595 elements
[index
].modifier
= modify
;
598 while (isdigit(dateString
[1]))
601 // check for "1st", "2nd, "3rd", "4th", ...
603 const char* suffixes
[] = {"th", "st", "nd", "rd"};
604 const char* validSuffix
= elements
[index
].value
> 3
605 ? "th" : suffixes
[elements
[index
].value
];
606 if (!strncasecmp(dateString
+ 1, validSuffix
, 2)
607 && !isalpha(dateString
[3])) {
608 // for now, just ignore the suffix - but we might be able
609 // to deduce some meaning out of it, since it's not really
610 // possible to put it in anywhere
613 } else if (isalpha(c
)) {
614 // fetch whole string
616 const char* string
= dateString
;
617 while (isalpha(dateString
[1]))
619 int32 length
= dateString
+ 1 - string
;
621 // compare with known strings
622 // ToDo: should understand other languages as well...
624 const known_identifier
* identifier
= kIdentifiers
;
625 for (; identifier
->string
; identifier
++) {
626 if (!strncasecmp(identifier
->string
, string
, length
)
627 && !identifier
->string
[length
])
630 if (identifier
->alternate_string
!= NULL
631 && !strncasecmp(identifier
->alternate_string
, string
, length
)
632 && !identifier
->alternate_string
[length
])
635 if (identifier
->string
== NULL
) {
636 // unknown string, we don't have to parse any further
640 if (index
> 0 && identifier
->type
== TYPE_UNIT
) {
641 // this is just a unit, so it will give the last value a meaning
643 if (elements
[--index
].value_type
!= VALUE_NUMERICAL
644 && !elements
[index
].IsNextLastThis())
647 elements
[index
].AdoptUnit(*identifier
);
648 } else if (index
> 0 && elements
[index
- 1].IsNextLastThis()) {
649 if (identifier
->type
== TYPE_MONTH
650 || identifier
->type
== TYPE_WEEKDAY
) {
653 switch (elements
[index
].value
) {
655 elements
[index
].modifier
= MODIFY_LAST
;
658 elements
[index
].modifier
= MODIFY_THIS
;
661 elements
[index
].modifier
= MODIFY_NEXT
;
664 elements
[index
].Adopt(*identifier
);
665 elements
[index
].type
= TYPE_UNIT
;
669 elements
[index
].Adopt(*identifier
);
673 // see if we can join any preceding modifiers
676 && elements
[index
- 1].type
== TYPE_MODIFIER
677 && (elements
[index
].flags
& FLAG_NOT_MODIFIABLE
) == 0) {
678 // copy the current one to the last and go on
679 elements
[index
].modifier
= elements
[index
- 1].modifier
;
680 elements
[index
].value
*= elements
[index
- 1].value
;
681 elements
[index
].flags
|= elements
[index
- 1].flags
;
682 elements
[index
- 1] = elements
[index
];
684 // we filled out one parsed_element
688 if (index
< MAX_ELEMENTS
)
689 memset(&elements
[index
], 0, sizeof(parsed_element
));
692 // were there any elements?
696 elements
[index
].type
= TYPE_END
;
703 computeRelativeUnit(parsed_element
& element
, struct tm
& tm
, int* _flags
)
705 // set the relative start depending on unit
707 switch (element
.unit
) {
709 tm
.tm_mon
= 0; // supposed to fall through
711 tm
.tm_mday
= 1; // supposed to fall through
721 if ((element
.flags
& FLAG_RELATIVE
) != 0) {
722 bigtime_t value
= element
.value
;
723 if (element
.modifier
== MODIFY_MINUS
)
724 value
= -element
.value
;
726 if (element
.unit
== UNIT_MONTH
)
728 else if (element
.unit
== UNIT_DAY
)
730 else if (element
.unit
== UNIT_SECOND
) {
732 *_flags
|= PARSEDATE_MINUTE_RELATIVE_TIME
;
733 } else if (element
.unit
== UNIT_YEAR
)
735 } else if (element
.base_type
== TYPE_WEEKDAY
) {
736 tm
.tm_mday
+= element
.value
- tm
.tm_wday
;
738 if (element
.modifier
== MODIFY_NEXT
)
740 else if (element
.modifier
== MODIFY_LAST
)
742 } else if (element
.base_type
== TYPE_MONTH
) {
743 tm
.tm_mon
= element
.value
- 1;
745 if (element
.modifier
== MODIFY_NEXT
)
747 else if (element
.modifier
== MODIFY_LAST
)
753 /*! Uses the format assignment (through "format", and "optional") for the
754 parsed elements and calculates the time value with respect to "now".
755 Will also set the day/minute relative flags in "_flags".
758 computeDate(const char* format
, bool* optional
, parsed_element
* elements
,
759 time_t now
, DateMask dateMask
, int* _flags
)
761 TRACE(("matches: %s\n", format
));
763 parsed_element
* element
= elements
;
771 if (dateMask
.IsComplete())
772 memset(&tm
, 0, sizeof(tm
));
774 localtime_r(&now
, &tm
);
775 nowYear
= tm
.tm_year
;
776 if (dateMask
.HasTime()) {
781 *_flags
= PARSEDATE_RELATIVE_TIME
;
784 while (element
->type
!= TYPE_END
) {
786 while (isspace(format
[0]))
789 if (format
[0] == '[' && format
[2] == ']') {
790 // does this optional parameter not match our date string?
791 if (!optional
[position
]) {
800 switch (element
->value_type
) {
802 // skip the single character
805 case VALUE_NUMERICAL
:
808 tm
.tm_mday
= element
->value
;
811 tm
.tm_mon
= element
->value
- 1;
815 tm
.tm_hour
= element
->value
;
818 tm
.tm_min
= element
->value
;
821 tm
.tm_sec
= element
->value
;
828 localtime_r(&now
, &tmNow
);
829 nowYear
= tmNow
.tm_year
;
831 int nowYearInCentury
= nowYear
% 100;
832 int nowCentury
= 1900 + nowYear
- nowYearInCentury
;
834 tm
.tm_year
= element
->value
;
835 if (tm
.tm_year
< 1900) {
836 // just a relative year like 11 (2011)
838 // interpret something like 50 as 1950 but
839 // something like 11 as 2011 (assuming now is 2011)
840 if (nowYearInCentury
+ 10 < tm
.tm_year
% 100)
843 tm
.tm_year
+= nowCentury
- 1900;
850 case 'z': // time zone
854 = (element
->value
- element
->value
% 100) * 36
855 + (element
->value
% 100) * 60;
856 if (element
->modifier
== MODIFY_MINUS
)
858 tm
.tm_sec
-= value
+ timezone
;
862 computeRelativeUnit(*element
, tm
, _flags
);
865 // there is no TYPE_DASH element for this (just a flag)
875 // we'll apply this element later, if still necessary
876 if (!dateMask
.IsComplete())
877 computeRelativeUnit(*element
, tm
, _flags
);
881 tm
.tm_mon
= element
->value
- 1;
883 case 'p': // meridian
884 tm
.tm_sec
+= element
->value
;
886 case 'z': // time zone
888 tm
.tm_sec
-= element
->value
+ timezone
;
890 case 'T': // time unit
891 if ((element
->flags
& FLAG_NOW
) != 0) {
892 *_flags
= PARSEDATE_MINUTE_RELATIVE_TIME
893 | PARSEDATE_RELATIVE_TIME
;
897 computeRelativeUnit(*element
, tm
, _flags
);
903 // format matched at this point, check next element
905 if (format
[0] == ']')
916 // #pragma mark - public API
920 parsedate_etc(const char* dateString
, time_t now
, int* _flags
)
922 // preparse date string so that it can be easily compared to our formats
924 parsed_element elements
[MAX_ELEMENTS
];
926 if (preparseDate(dateString
, elements
) < B_OK
) {
927 *_flags
= PARSEDATE_INVALID_DATE
;
932 printf("parsedate(\"%s\", now %ld)\n", dateString
, now
);
933 for (int32 index
= 0; elements
[index
].type
!= TYPE_END
; index
++) {
934 parsed_element e
= elements
[index
];
936 printf(" %ld: type = %u, base_type = %u, unit = %u, flags = %u, "
937 "modifier = %u, value = %Ld (%s)\n", index
, e
.type
, e
.base_type
,
938 e
.unit
, e
.flags
, e
.modifier
, e
.value
,
939 e
.value_type
== VALUE_NUMERICAL
? "numerical"
940 : (e
.value_type
== VALUE_STRING
? "string" : "char"));
944 bool optional
[MAX_ELEMENTS
];
946 for (int32 index
= 0; sFormatsTable
[index
]; index
++) {
947 // test if this format matches our date string
949 const char* format
= sFormatsTable
[index
];
953 parsed_element
* element
= elements
;
954 while (element
->type
!= TYPE_END
) {
956 while (isspace(format
[0]))
959 if (format
[0] == '[' && format
[2] == ']') {
960 optional
[position
] = true;
963 optional
[position
] = false;
965 switch (element
->value_type
) {
967 // check the allowed single characters
969 switch (element
->type
) {
971 if (format
[0] != '.')
975 if (format
[0] != '-')
979 if (format
[0] != ',')
983 if (format
[0] != ':')
991 case VALUE_NUMERICAL
:
992 // make sure that unit types are respected
993 if (element
->type
== TYPE_UNIT
&& format
[0] != 'T')
998 if (element
->value
> 31)
1001 dateMask
.Set(TYPE_DAY
);
1004 if (element
->value
> 12)
1007 dateMask
.Set(TYPE_MONTH
);
1011 if (element
->value
> 24)
1014 dateMask
.Set(TYPE_HOUR
);
1017 if (element
->value
> 59)
1020 dateMask
.Set(TYPE_MINUTE
);
1023 if (element
->value
> 59)
1026 dateMask
.Set(TYPE_SECOND
);
1030 // accept all values
1032 case 'z': // time zone
1034 // a numerical timezone must be introduced by '+'
1035 // or '-' and it must not exceed 2399
1036 if ((element
->modifier
!= MODIFY_MINUS
1037 && element
->modifier
!= MODIFY_PLUS
)
1038 || element
->value
> 2399)
1042 dateMask
.Set(TYPE_UNIT
);
1045 if ((element
->flags
& FLAG_HAS_DASH
) != 0) {
1046 element
--; // consider this element again
1049 // supposed to fall through
1056 switch (format
[0]) {
1057 case 'a': // weekday
1059 if (element
->type
!= TYPE_WEEKDAY
)
1064 if (element
->type
!= TYPE_MONTH
)
1067 dateMask
.Set(TYPE_MONTH
);
1069 case 'p': // meridian
1070 if (element
->type
!= TYPE_MERIDIAN
)
1073 case 'z': // time zone
1075 if (element
->type
!= TYPE_TIME_ZONE
)
1078 case 'T': // time unit
1079 if (element
->type
!= TYPE_UNIT
)
1082 dateMask
.Set(TYPE_UNIT
);
1090 // format matched at this point, check next element
1091 if (optional
[position
])
1099 // format didn't match element - let's see if the current
1100 // one is only optional (in which case we can continue)
1101 if (!optional
[position
])
1104 optional
[position
] = false;
1107 // skip the closing ']'
1110 // check if the format is already empty (since we reached our last
1113 if (format
[0] == '[')
1115 else if (isspace(format
[0]))
1123 // made it here? then we seem to have found our guy
1125 return computeDate(sFormatsTable
[index
], optional
, elements
, now
,
1129 // check if the next format has the same beginning as the skipped one,
1130 // and if so, skip that one, too.
1132 int32 length
= format
+ 1 - sFormatsTable
[index
];
1134 while (sFormatsTable
[index
+ 1]
1135 && !strncmp(sFormatsTable
[index
], sFormatsTable
[index
+ 1], length
))
1139 // didn't find any matching formats
1145 parsedate(const char* dateString
, time_t now
)
1149 return parsedate_etc(dateString
, now
, &flags
);
1154 set_dateformats(const char** table
)
1156 sFormatsTable
= table
? table
: kFormatsTable
;
1161 get_dateformats(void)
1163 return const_cast<const char**>(sFormatsTable
);