|
1 # -*- coding: latin-1 -*- |
|
2 |
|
3 """ Date/Time string parsing module. |
|
4 |
|
5 Note about the Y2K problems: |
|
6 |
|
7 The parser can only handle years with at least 2 digits. 2 |
|
8 digit year values get expanded by adding the century using |
|
9 DateTime.add_century(), while 3 digit year get converted |
|
10 literally. To have 2 digit years also be interpreted literally, |
|
11 add leading zeros, e.g. year 99 must be written as 099 or 0099. |
|
12 |
|
13 Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com |
|
14 Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com |
|
15 See the documentation for further information on copyrights, |
|
16 or contact the author. All Rights Reserved. |
|
17 |
|
18 """ |
|
19 import types,re,string |
|
20 import DateTime,ISO,ARPA,Timezone |
|
21 |
|
22 # Enable to produce debugging output |
|
23 _debug = 0 |
|
24 |
|
25 # REs for matching date and time parts in a string; These REs |
|
26 # parse a superset of ARPA, ISO, American and European style dates. |
|
27 # Timezones are supported via the Timezone submodule. |
|
28 |
|
29 _year = '(?P<year>-?\d+\d(?!:))' |
|
30 _fullyear = '(?P<year>-?\d+\d\d(?!:))' |
|
31 _year_epoch = '(?:' + _year + '(?P<epoch> *[ABCDE\.]+)?)' |
|
32 _fullyear_epoch = '(?:' + _fullyear + '(?P<epoch> *[ABCDE\.]+)?)' |
|
33 _relyear = '(?:\((?P<relyear>[-+]?\d+)\))' |
|
34 |
|
35 _month = '(?P<month>\d?\d(?!:))' |
|
36 _fullmonth = '(?P<month>\d\d(?!:))' |
|
37 _litmonth = ('(?P<litmonth>' |
|
38 'jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|' |
|
39 'mär|mae|mrz|mai|okt|dez|' |
|
40 'fev|avr|juin|juil|aou|aoû|déc|' |
|
41 'ene|abr|ago|dic|' |
|
42 'out' |
|
43 ')[a-z,\.;]*') |
|
44 litmonthtable = { |
|
45 # English |
|
46 'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6, |
|
47 'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12, |
|
48 # German |
|
49 'mär':3, 'mae':3, 'mrz':3, 'mai':5, 'okt':10, 'dez':12, |
|
50 # French |
|
51 'fev':2, 'avr':4, 'juin':6, 'juil':7, 'aou':8, 'aoû':8, |
|
52 'déc':12, |
|
53 # Spanish |
|
54 'ene':1, 'abr':4, 'ago':8, 'dic':12, |
|
55 # Portuguese |
|
56 'out':10, |
|
57 } |
|
58 _relmonth = '(?:\((?P<relmonth>[-+]?\d+)\))' |
|
59 |
|
60 _day = '(?P<day>\d?\d(?!:))' |
|
61 _usday = '(?P<day>\d?\d(?!:))(?:st|nd|rd|th|[,\.;])?' |
|
62 _fullday = '(?P<day>\d\d(?!:))' |
|
63 _litday = ('(?P<litday>' |
|
64 'mon|tue|wed|thu|fri|sat|sun|' |
|
65 'die|mit|don|fre|sam|son|' |
|
66 'lun|mar|mer|jeu|ven|sam|dim|' |
|
67 'mie|jue|vie|sab|dom|' |
|
68 'pri|seg|ter|cua|qui' |
|
69 ')[a-z]*') |
|
70 litdaytable = { |
|
71 # English |
|
72 'mon':0, 'tue':1, 'wed':2, 'thu':3, 'fri':4, 'sat':5, 'sun':6, |
|
73 # German |
|
74 'die':1, 'mit':2, 'don':3, 'fre':4, 'sam':5, 'son':6, |
|
75 # French |
|
76 'lun':0, 'mar':1, 'mer':2, 'jeu':3, 'ven':4, 'sam':5, 'dim':6, |
|
77 # Spanish |
|
78 'mie':2, 'jue':3, 'vie':4, 'sab':5, 'dom':6, |
|
79 # Portuguese |
|
80 'pri':0, 'seg':1, 'ter':2, 'cua':3, 'qui':4, |
|
81 } |
|
82 _relday = '(?:\((?P<relday>[-+]?\d+)\))' |
|
83 |
|
84 _hour = '(?P<hour>[012]?\d)' |
|
85 _minute = '(?P<minute>[0-6]\d)' |
|
86 _second = '(?P<second>[0-6]\d(?:[.,]\d+)?)' |
|
87 |
|
88 _days = '(?P<days>\d*\d(?:[.,]\d+)?)' |
|
89 _hours = '(?P<hours>\d*\d(?:[.,]\d+)?)' |
|
90 _minutes = '(?P<minutes>\d*\d(?:[.,]\d+)?)' |
|
91 _seconds = '(?P<seconds>\d*\d(?:[.,]\d+)?)' |
|
92 |
|
93 _reldays = '(?:\((?P<reldays>[-+]?\d+(?:[.,]\d+)?)\))' |
|
94 _relhours = '(?:\((?P<relhours>[-+]?\d+(?:[.,]\d+)?)\))' |
|
95 _relminutes = '(?:\((?P<relminutes>[-+]?\d+(?:[.,]\d+)?)\))' |
|
96 _relseconds = '(?:\((?P<relseconds>[-+]?\d+(?:[.,]\d+)?)\))' |
|
97 |
|
98 _sign = '(?:(?P<sign>[-+]) *)' |
|
99 _week = 'W(?P<week>\d?\d)' |
|
100 _zone = Timezone.zone |
|
101 _ampm = '(?P<ampm>[ap][m.]+)' |
|
102 |
|
103 _time = (_hour + ':' + _minute + '(?::' + _second + '|[^:]|$) *' |
|
104 + _ampm + '? *' + _zone + '?') |
|
105 _isotime = _hour + ':?' + _minute + ':?' + _second + '? *' + _zone + '?' |
|
106 |
|
107 _weekdate = _year + '-?(?:' + _week + '-?' + _day + '?)?' |
|
108 _eurodate = _day + '\.' + _month + '\.' + _year_epoch + '?' |
|
109 _usdate = _month + '/' + _day + '(?:/' + _year_epoch + '|[^/]|$)' |
|
110 _altusdate = _month + '-' + _day + '-' + _fullyear_epoch |
|
111 _isodate = _year + '-' + _month + '-?' + _day + '?(?!:)' |
|
112 _altisodate = _year + _fullmonth + _fullday + '(?!:)' |
|
113 _usisodate = _fullyear + '/' + _fullmonth + '/' + _fullday |
|
114 _litdate = ('(?:'+ _litday + ',? )? *' + |
|
115 _usday + ' *' + |
|
116 '[- ] *(?:' + _litmonth + '|'+ _month +') *[- ] *' + |
|
117 _year_epoch + '?') |
|
118 _altlitdate = ('(?:'+ _litday + ',? )? *' + |
|
119 _litmonth + '[ ,.a-z]+' + |
|
120 _usday + |
|
121 '(?:[ a-z]+' + _year_epoch + ')?') |
|
122 _eurlitdate = ('(?:'+ _litday + ',?[ a-z]+)? *' + |
|
123 '(?:'+ _usday + '[ a-z]+)? *' + |
|
124 _litmonth + |
|
125 '(?:[ ,.a-z]+' + _year_epoch + ')?') |
|
126 |
|
127 _relany = '[*%?a-zA-Z]+' |
|
128 |
|
129 _relisodate = ('(?:(?:' + _relany + '|' + _year + '|' + _relyear + ')-' + |
|
130 '(?:' + _relany + '|' + _month + '|' + _relmonth + ')-' + |
|
131 '(?:' + _relany + '|' + _day + '|' + _relday + '))') |
|
132 |
|
133 _asctime = ('(?:'+ _litday + ',? )? *' + |
|
134 _usday + ' *' + |
|
135 '[- ] *(?:' + _litmonth + '|'+ _month +') *[- ]' + |
|
136 '(?:[0-9: ]+)' + |
|
137 _year_epoch + '?') |
|
138 |
|
139 _relisotime = ('(?:(?:' + _relany + '|' + _hour + '|' + _relhours + '):' + |
|
140 '(?:' + _relany + '|' + _minute + '|' + _relminutes + ')' + |
|
141 '(?::(?:' + _relany + '|' + _second + '|' + _relseconds + '))?)') |
|
142 |
|
143 _isodelta1 = (_sign + '?' + |
|
144 _days + ':' + _hours + ':' + _minutes + ':' + _seconds) |
|
145 _isodelta2 = (_sign + '?' + |
|
146 _hours + ':' + _minutes + ':' + _seconds) |
|
147 _isodelta3 = (_sign + '?' + |
|
148 _hours + ':' + _minutes) |
|
149 _litdelta = (_sign + '?' + |
|
150 '(?:' + _days + ' *d[a-z]*[,; ]*)?' + |
|
151 '(?:' + _hours + ' *h[a-z]*[,; ]*)?' + |
|
152 '(?:' + _minutes + ' *m[a-z]*[,; ]*)?' + |
|
153 '(?:' + _seconds + ' *s[a-z]*[,; ]*)?') |
|
154 _litdelta2 = (_sign + '?' + |
|
155 '(?:' + _days + ' *d[a-z]*[,; ]*)?' + |
|
156 _hours + ':' + _minutes + '(?::' + _seconds + ')?') |
|
157 |
|
158 _timeRE = re.compile(_time, re.I) |
|
159 _isotimeRE = re.compile(_isotime, re.I) |
|
160 _isodateRE = re.compile(_isodate, re.I) |
|
161 _altisodateRE = re.compile(_altisodate, re.I) |
|
162 _usisodateRE = re.compile(_usisodate, re.I) |
|
163 _eurodateRE = re.compile(_eurodate, re.I) |
|
164 _usdateRE = re.compile(_usdate, re.I) |
|
165 _altusdateRE = re.compile(_altusdate, re.I) |
|
166 _litdateRE = re.compile(_litdate, re.I) |
|
167 _altlitdateRE = re.compile(_altlitdate, re.I) |
|
168 _eurlitdateRE = re.compile(_eurlitdate, re.I) |
|
169 _relisodateRE = re.compile(_relisodate, re.I) |
|
170 _asctimeRE = re.compile(_asctime, re.I) |
|
171 _isodelta1RE = re.compile(_isodelta1) |
|
172 _isodelta2RE = re.compile(_isodelta2) |
|
173 _isodelta3RE = re.compile(_isodelta3) |
|
174 _litdeltaRE = re.compile(_litdelta) |
|
175 _litdelta2RE = re.compile(_litdelta2) |
|
176 _relisotimeRE = re.compile(_relisotime, re.I) |
|
177 |
|
178 # Available date parsers |
|
179 _date_formats = ('euro', |
|
180 'usiso', 'us', 'altus', |
|
181 'iso', 'altiso', |
|
182 'lit', 'altlit', 'eurlit', |
|
183 'unknown') |
|
184 |
|
185 # Available time parsers |
|
186 _time_formats = ('standard', |
|
187 'iso', |
|
188 'unknown') |
|
189 |
|
190 def _parse_date(text, formats=_date_formats, defaultdate=None, |
|
191 |
|
192 int=int,float=float,lower=string.lower, |
|
193 add_century=DateTime.add_century, |
|
194 now=DateTime.now,us_formats=('us', 'altus'), |
|
195 iso_formats=('iso', 'altiso', 'usiso')): |
|
196 |
|
197 """ Parses the date part given in text and returns a tuple |
|
198 (text,day,month,year,style) with the following |
|
199 meanings: |
|
200 |
|
201 * text gives the original text without the date part |
|
202 |
|
203 * day,month,year give the parsed date |
|
204 |
|
205 * style gives information about which parser was successful: |
|
206 'euro' - the European date parser |
|
207 'us' - the US date parser |
|
208 'altus' - the alternative US date parser (with '-' instead of '/') |
|
209 'iso' - the ISO date parser |
|
210 'altiso' - the alternative ISO date parser (without '-') |
|
211 'usiso' - US style ISO date parser (yyyy/mm/dd) |
|
212 'lit' - the US literal date parser |
|
213 'altlit' - the alternative US literal date parser |
|
214 'eurlit' - the Eurpean literal date parser |
|
215 'unknown' - no date part was found, defaultdate was used |
|
216 |
|
217 formats may be set to a tuple of style strings specifying |
|
218 which of the above parsers to use and in which order to try |
|
219 them. Default is to try all of them in the above order. |
|
220 |
|
221 defaultdate provides the defaults to use in case no date part |
|
222 is found. Most other parsers default to the current year |
|
223 January 1 if some of these date parts are missing. |
|
224 |
|
225 If 'unknown' is not given in formats and the date cannot be |
|
226 parsed, a ValueError is raised. |
|
227 |
|
228 """ |
|
229 match = None |
|
230 style = '' |
|
231 |
|
232 # Apply parsers in the order given in formats |
|
233 for format in formats: |
|
234 |
|
235 if format == 'euro': |
|
236 # European style date |
|
237 match = _eurodateRE.search(text) |
|
238 if match is not None: |
|
239 day,month,year,epoch = match.groups() |
|
240 if year: |
|
241 if len(year) == 2: |
|
242 # Y2K problem: |
|
243 year = add_century(int(year)) |
|
244 else: |
|
245 year = int(year) |
|
246 else: |
|
247 if defaultdate is None: |
|
248 defaultdate = now() |
|
249 year = defaultdate.year |
|
250 if epoch and 'B' in epoch: |
|
251 year = -year + 1 |
|
252 month = int(month) |
|
253 day = int(day) |
|
254 # Could have mistaken euro format for us style date |
|
255 # which uses month, day order |
|
256 if month > 12 or month == 0: |
|
257 match = None |
|
258 continue |
|
259 break |
|
260 |
|
261 elif format in iso_formats: |
|
262 # ISO style date |
|
263 if format == 'iso': |
|
264 match = _isodateRE.search(text) |
|
265 elif format == 'altiso': |
|
266 match = _altisodateRE.search(text) |
|
267 # Avoid mistaking ISO time parts ('Thhmmss') for dates |
|
268 if match is not None: |
|
269 left, right = match.span() |
|
270 if left > 0 and \ |
|
271 text[left - 1:left] == 'T': |
|
272 match = None |
|
273 continue |
|
274 else: |
|
275 match = _usisodateRE.search(text) |
|
276 if match is not None: |
|
277 year,month,day = match.groups() |
|
278 if len(year) == 2: |
|
279 # Y2K problem: |
|
280 year = add_century(int(year)) |
|
281 else: |
|
282 year = int(year) |
|
283 # Default to January 1st |
|
284 if not month: |
|
285 month = 1 |
|
286 else: |
|
287 month = int(month) |
|
288 if not day: |
|
289 day = 1 |
|
290 else: |
|
291 day = int(day) |
|
292 break |
|
293 |
|
294 elif format in us_formats: |
|
295 # US style date |
|
296 if format == 'us': |
|
297 match = _usdateRE.search(text) |
|
298 else: |
|
299 match = _altusdateRE.search(text) |
|
300 if match is not None: |
|
301 month,day,year,epoch = match.groups() |
|
302 if year: |
|
303 if len(year) == 2: |
|
304 # Y2K problem: |
|
305 year = add_century(int(year)) |
|
306 else: |
|
307 year = int(year) |
|
308 else: |
|
309 if defaultdate is None: |
|
310 defaultdate = now() |
|
311 year = defaultdate.year |
|
312 if epoch and 'B' in epoch: |
|
313 year = -year + 1 |
|
314 # Default to 1 if no day is given |
|
315 if day: |
|
316 day = int(day) |
|
317 else: |
|
318 day = 1 |
|
319 month = int(month) |
|
320 # Could have mistaken us format for euro style date |
|
321 # which uses day, month order |
|
322 if month > 12 or month == 0: |
|
323 match = None |
|
324 continue |
|
325 break |
|
326 |
|
327 elif format == 'lit': |
|
328 # US style literal date |
|
329 match = _litdateRE.search(text) |
|
330 if match is not None: |
|
331 litday,day,litmonth,month,year,epoch = match.groups() |
|
332 break |
|
333 |
|
334 elif format == 'altlit': |
|
335 # Alternative US style literal date |
|
336 match = _altlitdateRE.search(text) |
|
337 if match is not None: |
|
338 litday,litmonth,day,year,epoch = match.groups() |
|
339 month = '<missing>' |
|
340 break |
|
341 |
|
342 elif format == 'eurlit': |
|
343 # European style literal date |
|
344 match = _eurlitdateRE.search(text) |
|
345 if match is not None: |
|
346 litday,day,litmonth,year,epoch = match.groups() |
|
347 month = '<missing>' |
|
348 break |
|
349 |
|
350 elif format == 'unknown': |
|
351 # No date part: use defaultdate |
|
352 if defaultdate is None: |
|
353 defaultdate = now() |
|
354 year = defaultdate.year |
|
355 month = defaultdate.month |
|
356 day = defaultdate.day |
|
357 style = format |
|
358 break |
|
359 |
|
360 # Check success |
|
361 if match is not None: |
|
362 # Remove date from text |
|
363 left, right = match.span() |
|
364 if 0 and _debug: |
|
365 print 'parsed date:',repr(text[left:right]),\ |
|
366 'giving:',year,month,day |
|
367 text = text[:left] + text[right:] |
|
368 style = format |
|
369 |
|
370 elif not style: |
|
371 # Not recognized: raise an error |
|
372 raise ValueError, 'unknown date format: "%s"' % text |
|
373 |
|
374 # Literal date post-processing |
|
375 if style in ('lit', 'altlit', 'eurlit'): |
|
376 if 0 and _debug: print match.groups() |
|
377 # Default to current year, January 1st |
|
378 if not year: |
|
379 if defaultdate is None: |
|
380 defaultdate = now() |
|
381 year = defaultdate.year |
|
382 else: |
|
383 if len(year) == 2: |
|
384 # Y2K problem: |
|
385 year = add_century(int(year)) |
|
386 else: |
|
387 year = int(year) |
|
388 if epoch and 'B' in epoch: |
|
389 year = -year + 1 |
|
390 if litmonth: |
|
391 litmonth = lower(litmonth) |
|
392 try: |
|
393 month = litmonthtable[litmonth] |
|
394 except KeyError: |
|
395 raise ValueError,\ |
|
396 'wrong month name: "%s"' % litmonth |
|
397 elif month: |
|
398 month = int(month) |
|
399 else: |
|
400 month = 1 |
|
401 if day: |
|
402 day = int(day) |
|
403 else: |
|
404 day = 1 |
|
405 |
|
406 #print '_parse_date:',text,day,month,year,style |
|
407 return text,day,month,year,style |
|
408 |
|
409 def _parse_time(text, formats=_time_formats, |
|
410 |
|
411 int=int,float=float,replace=string.replace): |
|
412 |
|
413 """ Parses a time part given in text and returns a tuple |
|
414 (text,hour,minute,second,offset,style) with the following |
|
415 meanings: |
|
416 |
|
417 * text gives the original text without the time part |
|
418 * hour,minute,second give the parsed time |
|
419 * offset gives the time zone UTC offset |
|
420 * style gives information about which parser was successful: |
|
421 'standard' - the standard parser |
|
422 'iso' - the ISO time format parser |
|
423 'unknown' - no time part was found |
|
424 |
|
425 formats may be set to a tuple specifying the parsers to use: |
|
426 'standard' - standard time format with ':' delimiter |
|
427 'iso' - ISO time format (superset of 'standard') |
|
428 'unknown' - default to 0:00:00, 0 zone offset |
|
429 |
|
430 If 'unknown' is not given in formats and the time cannot be |
|
431 parsed, a ValueError is raised. |
|
432 |
|
433 """ |
|
434 match = None |
|
435 style = '' |
|
436 |
|
437 # Apply parsers in the order given in formats |
|
438 for format in formats: |
|
439 |
|
440 # Standard format |
|
441 if format == 'standard': |
|
442 match = _timeRE.search(text) |
|
443 if match is not None: |
|
444 hour,minute,second,ampm,zone = match.groups() |
|
445 style = 'standard' |
|
446 break |
|
447 |
|
448 # ISO format |
|
449 if format == 'iso': |
|
450 match = _isotimeRE.search(text) |
|
451 if match is not None: |
|
452 hour,minute,second,zone = match.groups() |
|
453 ampm = None |
|
454 style = 'iso' |
|
455 break |
|
456 |
|
457 # Default handling |
|
458 elif format == 'unknown': |
|
459 hour,minute,second,offset = 0,0,0.0,0 |
|
460 style = 'unknown' |
|
461 break |
|
462 |
|
463 if not style: |
|
464 # If no default handling should be applied, raise an error |
|
465 raise ValueError, 'unknown time format: "%s"' % text |
|
466 |
|
467 # Post-processing |
|
468 if match is not None: |
|
469 if zone: |
|
470 # Convert to UTC offset |
|
471 offset = Timezone.utc_offset(zone) |
|
472 else: |
|
473 offset = 0 |
|
474 hour = int(hour) |
|
475 if ampm: |
|
476 if ampm[0] in ('p', 'P'): |
|
477 # 12pm = midday |
|
478 if hour < 12: |
|
479 hour = hour + 12 |
|
480 else: |
|
481 # 12am = midnight |
|
482 if hour >= 12: |
|
483 hour = hour - 12 |
|
484 if minute: |
|
485 minute = int(minute) |
|
486 else: |
|
487 minute = 0 |
|
488 if not second: |
|
489 second = 0.0 |
|
490 else: |
|
491 if ',' in second: |
|
492 second = replace(second, ',', '.') |
|
493 second = float(second) |
|
494 |
|
495 # Remove time from text |
|
496 left,right = match.span() |
|
497 if 0 and _debug: |
|
498 print 'parsed time:',repr(text[left:right]),\ |
|
499 'giving:',hour,minute,second,offset |
|
500 text = text[:left] + text[right:] |
|
501 |
|
502 #print '_parse_time:',text,hour,minute,second,offset,style |
|
503 return text,hour,minute,second,offset,style |
|
504 |
|
505 ### |
|
506 |
|
507 def DateTimeFromString(text, formats=_date_formats, defaultdate=None, |
|
508 time_formats=_time_formats, |
|
509 |
|
510 DateTime=DateTime): |
|
511 |
|
512 """ DateTimeFromString(text, [formats, defaultdate]) |
|
513 |
|
514 Returns a DateTime instance reflecting the date and time given |
|
515 in text. In case a timezone is given, the returned instance |
|
516 will point to the corresponding UTC time value. Otherwise, the |
|
517 value is set as given in the string. |
|
518 |
|
519 formats may be set to a tuple of strings specifying which of |
|
520 the following parsers to use and in which order to try |
|
521 them. Default is to try all of them in the order given below: |
|
522 |
|
523 'euro' - the European date parser |
|
524 'us' - the US date parser |
|
525 'altus' - the alternative US date parser (with '-' instead of '/') |
|
526 'iso' - the ISO date parser |
|
527 'altiso' - the alternative ISO date parser (without '-') |
|
528 'usiso' - US style ISO date parser (yyyy/mm/dd) |
|
529 'lit' - the US literal date parser |
|
530 'altlit' - the alternative US literal date parser |
|
531 'eurlit' - the Eurpean literal date parser |
|
532 'unknown' - if no date part is found, use defaultdate |
|
533 |
|
534 defaultdate provides the defaults to use in case no date part |
|
535 is found. Most of the parsers default to the current year |
|
536 January 1 if some of these date parts are missing. |
|
537 |
|
538 If 'unknown' is not given in formats and the date cannot |
|
539 be parsed, a ValueError is raised. |
|
540 |
|
541 time_formats may be set to a tuple of strings specifying which |
|
542 of the following parsers to use and in which order to try |
|
543 them. Default is to try all of them in the order given below: |
|
544 |
|
545 'standard' - standard time format HH:MM:SS (with ':' delimiter) |
|
546 'iso' - ISO time format (superset of 'standard') |
|
547 'unknown' - default to 00:00:00 in case the time format |
|
548 cannot be parsed |
|
549 |
|
550 Defaults to 00:00:00.00 for time parts that are not included |
|
551 in the textual representation. |
|
552 |
|
553 If 'unknown' is not given in time_formats and the time cannot |
|
554 be parsed, a ValueError is raised. |
|
555 |
|
556 """ |
|
557 origtext = text |
|
558 formats = tuple(formats) |
|
559 |
|
560 if formats is _date_formats or \ |
|
561 'iso' in formats or \ |
|
562 'altiso' in formats: |
|
563 |
|
564 # First try standard order (parse time, then date) |
|
565 if formats[0] not in ('iso', 'altiso'): |
|
566 text,hour,minute,second,offset,timestyle = _parse_time( |
|
567 origtext, |
|
568 time_formats) |
|
569 text,day,month,year,datestyle = _parse_date( |
|
570 text, |
|
571 formats + ('unknown',), |
|
572 defaultdate) |
|
573 if 0 and _debug: |
|
574 print 'tried time/date on %s, date=%s, time=%s' % (origtext, |
|
575 datestyle, |
|
576 timestyle) |
|
577 else: |
|
578 timestyle = 'iso' |
|
579 |
|
580 # If this fails, try the ISO order (date, then time) |
|
581 if timestyle in ('iso', 'unknown'): |
|
582 text,day,month,year,datestyle = _parse_date( |
|
583 origtext, |
|
584 formats, |
|
585 defaultdate) |
|
586 text,hour,minute,second,offset,timestyle = _parse_time( |
|
587 text, |
|
588 time_formats) |
|
589 if 0 and _debug: |
|
590 print 'tried ISO on %s, date=%s, time=%s' % (origtext, |
|
591 datestyle, |
|
592 timestyle) |
|
593 else: |
|
594 # Standard order: time part, then date part |
|
595 text,hour,minute,second,offset,timestyle = _parse_time( |
|
596 origtext, |
|
597 time_formats) |
|
598 text,day,month,year,datestyle = _parse_date( |
|
599 text, |
|
600 formats, |
|
601 defaultdate) |
|
602 |
|
603 if (datestyle == 'unknown' and 'unknown' not in formats) or \ |
|
604 (timestyle == 'unknown' and 'unknown' not in time_formats): |
|
605 raise ValueError,\ |
|
606 'Failed to parse "%s": found "%s" date, "%s" time' % \ |
|
607 (origtext, datestyle, timestyle) |
|
608 |
|
609 try: |
|
610 return DateTime.DateTime(year,month,day,hour,minute,second) - offset |
|
611 except DateTime.RangeError, why: |
|
612 raise DateTime.RangeError,\ |
|
613 'Failed to parse "%s": %s' % (origtext, why) |
|
614 |
|
615 def DateFromString(text, formats=_date_formats, defaultdate=None, |
|
616 |
|
617 DateTime=DateTime): |
|
618 |
|
619 """ DateFromString(text, [formats, defaultdate]) |
|
620 |
|
621 Returns a DateTime instance reflecting the date given in |
|
622 text. A possibly included time part is ignored. |
|
623 |
|
624 formats and defaultdate work just like for |
|
625 DateTimeFromString(). |
|
626 |
|
627 """ |
|
628 _text,day,month,year,datestyle = _parse_date(text, formats, defaultdate) |
|
629 |
|
630 if datestyle == 'unknown' and \ |
|
631 'unknown' not in formats: |
|
632 raise ValueError,\ |
|
633 'Failed to parse "%s": found "%s" date' % \ |
|
634 (origtext, datestyle) |
|
635 |
|
636 try: |
|
637 return DateTime.DateTime(year,month,day) |
|
638 except DateTime.RangeError, why: |
|
639 raise DateTime.RangeError,\ |
|
640 'Failed to parse "%s": %s' % (text, why) |
|
641 |
|
642 def validateDateTimeString(text, formats=_date_formats): |
|
643 |
|
644 """ validateDateTimeString(text, [formats, defaultdate]) |
|
645 |
|
646 Validates the given text and returns 1/0 depending on whether |
|
647 text includes parseable date and time values or not. |
|
648 |
|
649 formats works just like for DateTimeFromString() and defines |
|
650 the order of date/time parsers to apply. It defaults to the |
|
651 same list of parsers as for DateTimeFromString(). |
|
652 |
|
653 XXX Undocumented ! |
|
654 |
|
655 """ |
|
656 formats = list(formats) |
|
657 if 'unknown' in formats: |
|
658 formats.remove('unknown') |
|
659 try: |
|
660 DateTimeFromString(text, formats) |
|
661 except (DateTime.RangeError, ValueError), why: |
|
662 return 0 |
|
663 return 1 |
|
664 |
|
665 def validateDateString(text, formats=_date_formats): |
|
666 |
|
667 """ validateDateString(text, [formats, defaultdate]) |
|
668 |
|
669 Validates the given text and returns 1/0 depending on whether |
|
670 text includes a parseable date value or not. |
|
671 |
|
672 formats works just like for DateTimeFromString() and defines |
|
673 the order of date/time parsers to apply. It defaults to the |
|
674 same list of parsers as for DateTimeFromString(). |
|
675 |
|
676 XXX Undocumented ! |
|
677 |
|
678 """ |
|
679 formats = list(formats) |
|
680 if 'unknown' in formats: |
|
681 formats.remove('unknown') |
|
682 try: |
|
683 DateFromString(text, formats) |
|
684 except (DateTime.RangeError, ValueError), why: |
|
685 return 0 |
|
686 return 1 |
|
687 |
|
688 def TimeFromString(text, formats=_time_formats, |
|
689 |
|
690 DateTime=DateTime): |
|
691 |
|
692 """ TimeFromString(text, [formats]) |
|
693 |
|
694 Returns a DateTimeDelta instance reflecting the time given in |
|
695 text. A possibly included date part is ignored. |
|
696 |
|
697 formats may be set to a tuple of strings specifying which of |
|
698 the following parsers to use and in which order to try |
|
699 them. Default is to try all of them in the order given below: |
|
700 |
|
701 'standard' - standard time format with ':' delimiter |
|
702 'iso' - ISO time format (superset of 'standard') |
|
703 'unknown' - default to 00:00:00 in case the time format |
|
704 cannot be parsed |
|
705 |
|
706 Defaults to 00:00:00.00 for parts that are not included in the |
|
707 textual representation. |
|
708 |
|
709 """ |
|
710 _text,hour,minute,second,offset,timestyle = _parse_time( |
|
711 text, |
|
712 formats) |
|
713 |
|
714 if timestyle == 'unknown' and \ |
|
715 'unknown' not in formats: |
|
716 raise ValueError,\ |
|
717 'Failed to parse "%s": found "%s" time' % \ |
|
718 (text, timestyle) |
|
719 |
|
720 try: |
|
721 dtd = DateTime.DateTimeDelta(0.0, hour, minute, second) |
|
722 except DateTime.RangeError, why: |
|
723 raise DateTime.RangeError,\ |
|
724 'Failed to parse "%s": %s' % (text, why) |
|
725 else: |
|
726 # XXX What to do with offset ? |
|
727 return dtd |
|
728 |
|
729 # |
|
730 # XXX Still missing: validateTimeString(), validateDateTimeDeltaString() |
|
731 # and validateTimeDeltaString() |
|
732 # |
|
733 |
|
734 def DateTimeDeltaFromString(text, |
|
735 |
|
736 float=float,DateTime=DateTime): |
|
737 |
|
738 """ DateTimeDeltaFromString(text) |
|
739 |
|
740 Returns a DateTimeDelta instance reflecting the delta given in |
|
741 text. Defaults to 0:00:00:00.00 for parts that are not |
|
742 included in the textual representation or cannot be parsed. |
|
743 |
|
744 """ |
|
745 match = _isodelta1RE.search(text) |
|
746 if match is not None: |
|
747 sign, days, hours, minutes, seconds = match.groups() |
|
748 else: |
|
749 match = _litdelta2RE.search(text) |
|
750 if match is not None: |
|
751 sign, days, hours, minutes, seconds = match.groups() |
|
752 else: |
|
753 match = _isodelta2RE.search(text) |
|
754 if match is not None: |
|
755 sign, hours, minutes, seconds = match.groups() |
|
756 days = None |
|
757 else: |
|
758 match = _isodelta3RE.search(text) |
|
759 if match is not None: |
|
760 sign, hours, minutes = match.groups() |
|
761 days = None |
|
762 seconds = None |
|
763 else: |
|
764 match = _litdeltaRE.search(text) |
|
765 if match is not None: |
|
766 sign, days, hours, minutes, seconds = match.groups() |
|
767 |
|
768 else: |
|
769 # Not matched: |
|
770 return DateTime.DateTimeDelta(0.0) |
|
771 |
|
772 # Conversions |
|
773 if days: |
|
774 days = float(days) |
|
775 else: |
|
776 days = 0.0 |
|
777 if hours: |
|
778 hours = float(hours) |
|
779 else: |
|
780 hours = 0.0 |
|
781 if minutes: |
|
782 minutes = float(minutes) |
|
783 else: |
|
784 minutes = 0.0 |
|
785 if seconds: |
|
786 seconds = float(seconds) |
|
787 else: |
|
788 seconds = 0.0 |
|
789 if sign != '-': |
|
790 sign = 1 |
|
791 else: |
|
792 sign = -1 |
|
793 |
|
794 try: |
|
795 dtd = DateTime.DateTimeDelta(days,hours,minutes,seconds) |
|
796 except DateTime.RangeError, why: |
|
797 raise DateTime.RangeError,\ |
|
798 'Failed to parse "%s": %s' % (text, why) |
|
799 else: |
|
800 if sign < 0: |
|
801 return -dtd |
|
802 else: |
|
803 return dtd |
|
804 |
|
805 # Aliases |
|
806 TimeDeltaFromString = DateTimeDeltaFromString |
|
807 |
|
808 ### |
|
809 |
|
810 def _parse_reldate(text, |
|
811 |
|
812 int=int,float=float): |
|
813 |
|
814 match = _relisodateRE.search(text) |
|
815 if match is not None: |
|
816 groups = match.groups() |
|
817 if 0 and _debug: print groups |
|
818 year,years,month,months,day,days = groups |
|
819 if year: |
|
820 year = int(year) |
|
821 if years: |
|
822 years = float(years) |
|
823 else: |
|
824 years = 0 |
|
825 if month: |
|
826 month = int(month) |
|
827 if months: |
|
828 months = float(months) |
|
829 else: |
|
830 months = 0 |
|
831 if day: |
|
832 day = int(day) |
|
833 if days: |
|
834 days = float(days) |
|
835 else: |
|
836 days = 0 |
|
837 return year,years,month,months,day,days |
|
838 else: |
|
839 return None,0,None,0,None,0 |
|
840 |
|
841 def _parse_reltime(text, |
|
842 |
|
843 int=int,float=float): |
|
844 |
|
845 match = _relisotimeRE.search(text) |
|
846 if match is not None: |
|
847 groups = match.groups() |
|
848 if 0 and _debug: print groups |
|
849 hour,hours,minute,minutes,second,seconds = groups |
|
850 if hour: |
|
851 hour = int(hour) |
|
852 if hours: |
|
853 hours = float(hours) |
|
854 else: |
|
855 hours = 0 |
|
856 if minute: |
|
857 minute = int(minute) |
|
858 if minutes: |
|
859 minutes = float(minutes) |
|
860 else: |
|
861 minutes = 0 |
|
862 if second: |
|
863 second = int(second) |
|
864 if seconds: |
|
865 seconds = float(seconds) |
|
866 else: |
|
867 seconds = 0 |
|
868 return hour,hours,minute,minutes,second,seconds |
|
869 else: |
|
870 return None,0,None,0,None,0 |
|
871 |
|
872 def RelativeDateTimeFromString(text, |
|
873 |
|
874 RelativeDateTime=DateTime.RelativeDateTime): |
|
875 |
|
876 """ RelativeDateTimeFromString(text) |
|
877 |
|
878 Returns a RelativeDateTime instance reflecting the relative |
|
879 date and time given in text. |
|
880 |
|
881 Defaults to wildcards for parts or values which are not |
|
882 included in the textual representation or cannot be parsed. |
|
883 |
|
884 The format used in text must adhere to the following syntax: |
|
885 |
|
886 [YYYY-MM-DD] [HH:MM[:SS]] |
|
887 |
|
888 with the usual meanings. Values which should not be altered |
|
889 may be replaced with '*', '%', '?' or any combination of |
|
890 letters, e.g. 'YYYY'. Relative settings must be enclosed in |
|
891 parenthesis if given and should include a sign, e.g. '(+0001)' |
|
892 for the year part. All other settings are interpreted as |
|
893 absolute values. |
|
894 |
|
895 Date and time parts are both optional as a whole. Seconds in |
|
896 the time part are optional too. Everything else (including the |
|
897 hyphens and colons) is mandatory. |
|
898 |
|
899 """ |
|
900 year,years,month,months,day,days = _parse_reldate(text) |
|
901 hour,hours,minute,minutes,second,seconds = _parse_reltime(text) |
|
902 return RelativeDateTime(year=year,years=years, |
|
903 month=month,months=months, |
|
904 day=day,days=days, |
|
905 hour=hour,hours=hours, |
|
906 minute=minute,minutes=minutes, |
|
907 second=second,seconds=seconds) |
|
908 |
|
909 def RelativeDateFromString(text, |
|
910 |
|
911 RelativeDateTime=DateTime.RelativeDateTime): |
|
912 |
|
913 """ RelativeDateFromString(text) |
|
914 |
|
915 Same as RelativeDateTimeFromString(text) except that only the |
|
916 date part of text is taken into account. |
|
917 |
|
918 """ |
|
919 year,years,month,months,day,days = _parse_reldate(text) |
|
920 return RelativeDateTime(year=year,years=years, |
|
921 month=month,months=months, |
|
922 day=day,days=days) |
|
923 |
|
924 def RelativeTimeFromString(text, |
|
925 |
|
926 RelativeDateTime=DateTime.RelativeDateTime): |
|
927 |
|
928 """ RelativeTimeFromString(text) |
|
929 |
|
930 Same as RelativeDateTimeFromString(text) except that only the |
|
931 time part of text is taken into account. |
|
932 |
|
933 """ |
|
934 hour,hours,minute,minutes,second,seconds = _parse_reltime(text) |
|
935 return RelativeDateTime(hour=hour,hours=hours, |
|
936 minute=minute,minutes=minutes, |
|
937 second=second,seconds=seconds) |
|
938 |
|
939 ### Tests |
|
940 |
|
941 def _test(): |
|
942 |
|
943 import sys |
|
944 |
|
945 t = DateTime.now() |
|
946 |
|
947 print 'Testing DateTime Parser...' |
|
948 |
|
949 l = [ |
|
950 |
|
951 # Literal formats |
|
952 ('Sun Nov 6 08:49:37 1994', '1994-11-06 08:49:37.00'), |
|
953 ('sun nov 6 08:49:37 1994', '1994-11-06 08:49:37.00'), |
|
954 ('sUN NOV 6 08:49:37 1994', '1994-11-06 08:49:37.00'), |
|
955 ('Sunday, 06-Nov-94 08:49:37 GMT', '1994-11-06 08:49:37.00'), |
|
956 ('Sun, 06 Nov 1994 08:49:37 GMT', '1994-11-06 08:49:37.00'), |
|
957 ('06-Nov-94 08:49:37', '1994-11-06 08:49:37.00'), |
|
958 ('06-Nov-94', '1994-11-06 00:00:00.00'), |
|
959 ('06-NOV-94', '1994-11-06 00:00:00.00'), |
|
960 ('November 19 08:49:37', '%s-11-19 08:49:37.00' % t.year), |
|
961 ('Nov. 9', '%s-11-09 00:00:00.00' % t.year), |
|
962 ('Sonntag, der 6. November 1994, 08:49:37 GMT', '1994-11-06 08:49:37.00'), |
|
963 ('6. November 2001, 08:49:37', '2001-11-06 08:49:37.00'), |
|
964 ('sep 6', '%s-09-06 00:00:00.00' % t.year), |
|
965 ('sep 6 2000', '2000-09-06 00:00:00.00'), |
|
966 ('September 29', '%s-09-29 00:00:00.00' % t.year), |
|
967 ('Sep. 29', '%s-09-29 00:00:00.00' % t.year), |
|
968 ('6 sep', '%s-09-06 00:00:00.00' % t.year), |
|
969 ('29 September', '%s-09-29 00:00:00.00' % t.year), |
|
970 ('29 Sep.', '%s-09-29 00:00:00.00' % t.year), |
|
971 ('sep 6 2001', '2001-09-06 00:00:00.00'), |
|
972 ('Sep 6, 2001', '2001-09-06 00:00:00.00'), |
|
973 ('September 6, 2001', '2001-09-06 00:00:00.00'), |
|
974 ('sep 6 01', '2001-09-06 00:00:00.00'), |
|
975 ('Sep 6, 01', '2001-09-06 00:00:00.00'), |
|
976 ('September 6, 01', '2001-09-06 00:00:00.00'), |
|
977 ('30 Apr 2006 20:19:00', '2006-04-30 20:19:00.00'), |
|
978 |
|
979 # ISO formats |
|
980 ('1994-11-06 08:49:37', '1994-11-06 08:49:37.00'), |
|
981 ('010203', '2001-02-03 00:00:00.00'), |
|
982 ('2001-02-03 00:00:00.00', '2001-02-03 00:00:00.00'), |
|
983 ('2001-02 00:00:00.00', '2001-02-01 00:00:00.00'), |
|
984 ('2001-02-03', '2001-02-03 00:00:00.00'), |
|
985 ('2001-02', '2001-02-01 00:00:00.00'), |
|
986 ('20000824/2300', '2000-08-24 23:00:00.00'), |
|
987 ('20000824/0102', '2000-08-24 01:02:00.00'), |
|
988 ('20000824', '2000-08-24 00:00:00.00'), |
|
989 ('20000824/020301', '2000-08-24 02:03:01.00'), |
|
990 ('20000824 020301', '2000-08-24 02:03:01.00'), |
|
991 ('-20000824 020301', '-2000-08-24 02:03:01.00'), |
|
992 ('20000824T020301', '2000-08-24 02:03:01.00'), |
|
993 ('20000824 020301', '2000-08-24 02:03:01.00'), |
|
994 ('2000-08-24 02:03:01.00', '2000-08-24 02:03:01.00'), |
|
995 ('T020311', '%s 02:03:11.00' % t.date), |
|
996 ('2003-12-9', '2003-12-09 00:00:00.00'), |
|
997 ('03-12-9', '2003-12-09 00:00:00.00'), |
|
998 ('003-12-9', '0003-12-09 00:00:00.00'), |
|
999 ('0003-12-9', '0003-12-09 00:00:00.00'), |
|
1000 ('2003-1-9', '2003-01-09 00:00:00.00'), |
|
1001 ('03-1-9', '2003-01-09 00:00:00.00'), |
|
1002 ('003-1-9', '0003-01-09 00:00:00.00'), |
|
1003 ('0003-1-9', '0003-01-09 00:00:00.00'), |
|
1004 |
|
1005 # US formats |
|
1006 ('06/11/94 08:49:37', '1994-06-11 08:49:37.00'), |
|
1007 ('11/06/94 08:49:37', '1994-11-06 08:49:37.00'), |
|
1008 ('9/23/2001', '2001-09-23 00:00:00.00'), |
|
1009 ('9-23-2001', '2001-09-23 00:00:00.00'), |
|
1010 ('9/6', '%s-09-06 00:00:00.00' % t.year), |
|
1011 ('09/6', '%s-09-06 00:00:00.00' % t.year), |
|
1012 ('9/06', '%s-09-06 00:00:00.00' % t.year), |
|
1013 ('09/06', '%s-09-06 00:00:00.00' % t.year), |
|
1014 ('9/6/2001', '2001-09-06 00:00:00.00'), |
|
1015 ('09/6/2001', '2001-09-06 00:00:00.00'), |
|
1016 ('9/06/2001', '2001-09-06 00:00:00.00'), |
|
1017 ('09/06/2001', '2001-09-06 00:00:00.00'), |
|
1018 ('9-6-2001', '2001-09-06 00:00:00.00'), |
|
1019 ('09-6-2001', '2001-09-06 00:00:00.00'), |
|
1020 ('9-06-2001', '2001-09-06 00:00:00.00'), |
|
1021 ('09-06-2001', '2001-09-06 00:00:00.00'), |
|
1022 ('2002/05/28 13:10:56.1147 GMT+2', '2002-05-28 13:10:56.11'), |
|
1023 ('1970/01/01', '1970-01-01 00:00:00.00'), |
|
1024 ('20021025 12:00 PM', '2002-10-25 12:00:00.00'), |
|
1025 ('20021025 12:30 PM', '2002-10-25 12:30:00.00'), |
|
1026 ('20021025 12:00 AM', '2002-10-25 00:00:00.00'), |
|
1027 ('20021025 12:30 AM', '2002-10-25 00:30:00.00'), |
|
1028 ('20021025 1:00 PM', '2002-10-25 13:00:00.00'), |
|
1029 ('20021025 2:00 AM', '2002-10-25 02:00:00.00'), |
|
1030 ('Thursday, February 06, 2003 12:40 PM', '2003-02-06 12:40:00.00'), |
|
1031 ('Mon, 18 Sep 2006 23:03:00', '2006-09-18 23:03:00.00'), |
|
1032 |
|
1033 # European formats |
|
1034 ('6.11.2001, 08:49:37', '2001-11-06 08:49:37.00'), |
|
1035 ('06.11.2001, 08:49:37', '2001-11-06 08:49:37.00'), |
|
1036 ('06.11. 08:49:37', '%s-11-06 08:49:37.00' % t.year), |
|
1037 #('21/12/2002', '2002-12-21 00:00:00.00'), |
|
1038 #('21/08/2002', '2002-08-21 00:00:00.00'), |
|
1039 #('21-08-2002', '2002-08-21 00:00:00.00'), |
|
1040 #('13/01/03', '2003-01-13 00:00:00.00'), |
|
1041 #('13/1/03', '2003-01-13 00:00:00.00'), |
|
1042 #('13/1/3', '2003-01-13 00:00:00.00'), |
|
1043 #('13/01/3', '2003-01-13 00:00:00.00'), |
|
1044 |
|
1045 # Time only formats |
|
1046 ('01:03', '%s 01:03:00.00' % t.date), |
|
1047 ('01:03:11', '%s 01:03:11.00' % t.date), |
|
1048 ('01:03:11.50', '%s 01:03:11.50' % t.date), |
|
1049 ('01:03:11.50 AM', '%s 01:03:11.50' % t.date), |
|
1050 ('01:03:11.50 PM', '%s 13:03:11.50' % t.date), |
|
1051 ('01:03:11.50 a.m.', '%s 01:03:11.50' % t.date), |
|
1052 ('01:03:11.50 p.m.', '%s 13:03:11.50' % t.date), |
|
1053 |
|
1054 # Invalid formats |
|
1055 ('6..2001, 08:49:37', '%s 08:49:37.00' % t.date), |
|
1056 ('9//2001', 'ignore'), |
|
1057 ('06--94 08:49:37', 'ignore'), |
|
1058 ('20000824020301', 'ignore'), |
|
1059 ('20-03 00:00:00.00', 'ignore'), |
|
1060 ('9/2001', 'ignore'), |
|
1061 ('9-6', 'ignore'), |
|
1062 ('09-6', 'ignore'), |
|
1063 ('9-06', 'ignore'), |
|
1064 ('09-06', 'ignore'), |
|
1065 ('20000824/23', 'ignore'), |
|
1066 ('November 1994 08:49:37', 'ignore'), |
|
1067 ('Nov. 94', 'ignore'), |
|
1068 ('Mon, 18 Sep 2006 23:03:00 +1234567890', 'ignore'), |
|
1069 |
|
1070 ] |
|
1071 |
|
1072 # Add Unicode versions |
|
1073 try: |
|
1074 unicode |
|
1075 except NameError: |
|
1076 pass |
|
1077 else: |
|
1078 k = [] |
|
1079 for text, result in l: |
|
1080 k.append((unicode(text), result)) |
|
1081 l.extend(k) |
|
1082 |
|
1083 for text, reference in l: |
|
1084 try: |
|
1085 value = DateTimeFromString(text) |
|
1086 except: |
|
1087 if reference is None: |
|
1088 continue |
|
1089 else: |
|
1090 value = str(sys.exc_info()[1]) |
|
1091 valid_datetime = validateDateTimeString(text) |
|
1092 valid_date = validateDateString(text) |
|
1093 if str(value) != reference and \ |
|
1094 not reference == 'ignore': |
|
1095 print 'Failed to parse "%s"' % text |
|
1096 print ' expected: %s' % (reference or '<exception>') |
|
1097 print ' parsed: %s' % value |
|
1098 elif _debug: |
|
1099 print 'Parsed "%s" successfully' % text |
|
1100 if _debug: |
|
1101 if not valid_datetime: |
|
1102 print ' "%s" failed date/time validation' % text |
|
1103 if not valid_date: |
|
1104 print ' "%s" failed date validation' % text |
|
1105 |
|
1106 et = DateTime.now() |
|
1107 print 'done. (after %f seconds)' % ((et-t).seconds) |
|
1108 |
|
1109 ### |
|
1110 |
|
1111 print 'Testing DateTimeDelta Parser...' |
|
1112 |
|
1113 t = DateTime.now() |
|
1114 l = [ |
|
1115 |
|
1116 # Literal formats |
|
1117 ('Sun Nov 6 08:49:37 1994', '08:49:37.00'), |
|
1118 ('1 day, 8 hours, 49 minutes, 37 seconds', '1:08:49:37.00'), |
|
1119 ('10 days, 8 hours, 49 minutes, 37 seconds', '10:08:49:37.00'), |
|
1120 ('8 hours, 49 minutes, 37 seconds', '08:49:37.00'), |
|
1121 ('49 minutes, 37 seconds', '00:49:37.00'), |
|
1122 ('37 seconds', '00:00:37.00'), |
|
1123 ('37.5 seconds', '00:00:37.50'), |
|
1124 ('8 hours later', '08:00:00.00'), |
|
1125 ('2 days', '2:00:00:00.00'), |
|
1126 ('2 days 23h', '2:23:00:00.00'), |
|
1127 ('2 days 23:57', '2:23:57:00.00'), |
|
1128 ('2 days 23:57:13', '2:23:57:13.00'), |
|
1129 ('', '00:00:00.00'), |
|
1130 |
|
1131 # ISO formats |
|
1132 ('1994-11-06 08:49:37', '08:49:37.00'), |
|
1133 ('10:08:49:37', '10:08:49:37.00'), |
|
1134 ('08:49:37', '08:49:37.00'), |
|
1135 ('08:49', '08:49:00.00'), |
|
1136 ('-10:08:49:37', '-10:08:49:37.00'), |
|
1137 ('-08:49:37', '-08:49:37.00'), |
|
1138 ('-08:49', '-08:49:00.00'), |
|
1139 ('- 10:08:49:37', '-10:08:49:37.00'), |
|
1140 ('- 08:49:37', '-08:49:37.00'), |
|
1141 ('- 08:49', '-08:49:00.00'), |
|
1142 ('10:08:49:37.5', '10:08:49:37.50'), |
|
1143 ('08:49:37.5', '08:49:37.50'), |
|
1144 ('10:8:49:37', '10:08:49:37.00'), |
|
1145 ('8:9:37', '08:09:37.00'), |
|
1146 ('8:9', '08:09:00.00'), |
|
1147 ('8', '00:00:00.00'), |
|
1148 |
|
1149 # Invalid formats |
|
1150 #('', None), |
|
1151 #('8', None), |
|
1152 |
|
1153 ] |
|
1154 |
|
1155 for text, reference in l: |
|
1156 try: |
|
1157 value = DateTimeDeltaFromString(text) |
|
1158 except: |
|
1159 if reference is None: |
|
1160 continue |
|
1161 else: |
|
1162 value = str(sys.exc_info()[1]) |
|
1163 if str(value) != reference and \ |
|
1164 not reference == 'ignore': |
|
1165 print 'Failed to parse "%s"' % text |
|
1166 print ' expected: %s' % (reference or '<exception>') |
|
1167 print ' parsed: %s' % value |
|
1168 elif _debug: |
|
1169 print 'Parsed "%s" successfully' % text |
|
1170 |
|
1171 et = DateTime.now() |
|
1172 print 'done. (after %f seconds)' % ((et-t).seconds) |
|
1173 |
|
1174 ### |
|
1175 |
|
1176 print 'Testing Time Parser...' |
|
1177 |
|
1178 t = DateTime.now() |
|
1179 l = [ |
|
1180 |
|
1181 # Standard formats |
|
1182 ('08:49:37 AM', '08:49:37.00'), |
|
1183 ('08:49:37 PM', '20:49:37.00'), |
|
1184 ('12:00:00 AM', '00:00:00.00'), |
|
1185 ('12:00:00 PM', '12:00:00.00'), |
|
1186 ('8:09:37', '08:09:37.00'), |
|
1187 ('8:09', '08:09:00.00'), |
|
1188 |
|
1189 # ISO formats |
|
1190 ('08:49:37', '08:49:37.00'), |
|
1191 ('08:49', '08:49:00.00'), |
|
1192 ('08:49:37.5', '08:49:37.50'), |
|
1193 ('08:49:37,5', '08:49:37.50'), |
|
1194 ('08:09', '08:09:00.00'), |
|
1195 |
|
1196 # Invalid formats |
|
1197 ('', None), |
|
1198 ('8:9:37', 'XXX Should give an exception'), |
|
1199 ('08:9:37', 'XXX Should give an exception'), |
|
1200 ('8:9', None), |
|
1201 ('8', None), |
|
1202 |
|
1203 ] |
|
1204 |
|
1205 for text, reference in l: |
|
1206 try: |
|
1207 value = TimeFromString(text, formats=('standard', 'iso')) |
|
1208 except: |
|
1209 if reference is None: |
|
1210 continue |
|
1211 else: |
|
1212 value = str(sys.exc_info()[1]) |
|
1213 if str(value) != reference and \ |
|
1214 not reference == 'ignore': |
|
1215 print 'Failed to parse "%s"' % text |
|
1216 print ' expected: %s' % (reference or '<exception>') |
|
1217 print ' parsed: %s' % value |
|
1218 elif _debug: |
|
1219 print 'Parsed "%s" successfully' % text |
|
1220 |
|
1221 et = DateTime.now() |
|
1222 print 'done. (after %f seconds)' % ((et-t).seconds) |
|
1223 |
|
1224 if __name__ == '__main__': |
|
1225 _test() |