parser.py (31799B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\dateutil\parser.py 2 from __future__ import unicode_literals 3 import datetime 4 import string 5 import time 6 import collections 7 import re 8 from io import StringIO 9 from calendar import monthrange, isleap 10 from six import text_type, binary_type, integer_types 11 from . import relativedelta 12 from . import tz 13 __all__ = [u'parse', u'parserinfo'] 14 15 class _timelex(object): 16 _split_decimal = re.compile(u'([\\.,])') 17 18 def __init__(self, instream): 19 if isinstance(instream, binary_type): 20 instream = instream.decode() 21 if isinstance(instream, text_type): 22 instream = StringIO(instream) 23 if getattr(instream, u'read', None) is None: 24 raise TypeError(u'Parser must be a string or character stream, not {itype}'.format(itype=instream.__class__.__name__)) 25 self.instream = instream 26 self.charstack = [] 27 self.tokenstack = [] 28 self.eof = False 29 30 def get_token(self): 31 if self.tokenstack: 32 return self.tokenstack.pop(0) 33 seenletters = False 34 token = None 35 state = None 36 while not self.eof: 37 if self.charstack: 38 nextchar = self.charstack.pop(0) 39 else: 40 nextchar = self.instream.read(1) 41 while nextchar == u'\x00': 42 nextchar = self.instream.read(1) 43 44 if not nextchar: 45 self.eof = True 46 break 47 elif not state: 48 token = nextchar 49 if self.isword(nextchar): 50 state = u'a' 51 elif self.isnum(nextchar): 52 state = u'0' 53 elif self.isspace(nextchar): 54 token = u' ' 55 break 56 else: 57 break 58 elif state == u'a': 59 seenletters = True 60 if self.isword(nextchar): 61 token += nextchar 62 elif nextchar == u'.': 63 token += nextchar 64 state = u'a.' 65 else: 66 self.charstack.append(nextchar) 67 break 68 elif state == u'0': 69 if self.isnum(nextchar): 70 token += nextchar 71 elif nextchar == u'.' or nextchar == u',' and len(token) >= 2: 72 token += nextchar 73 state = u'0.' 74 else: 75 self.charstack.append(nextchar) 76 break 77 elif state == u'a.': 78 seenletters = True 79 if nextchar == u'.' or self.isword(nextchar): 80 token += nextchar 81 elif self.isnum(nextchar) and token[-1] == u'.': 82 token += nextchar 83 state = u'0.' 84 else: 85 self.charstack.append(nextchar) 86 break 87 elif state == u'0.': 88 if nextchar == u'.' or self.isnum(nextchar): 89 token += nextchar 90 elif self.isword(nextchar) and token[-1] == u'.': 91 token += nextchar 92 state = u'a.' 93 else: 94 self.charstack.append(nextchar) 95 break 96 97 if state in (u'a.', u'0.') and (seenletters or token.count(u'.') > 1 or token[-1] in u'.,'): 98 l = self._split_decimal.split(token) 99 token = l[0] 100 for tok in l[1:]: 101 if tok: 102 self.tokenstack.append(tok) 103 104 if state == u'0.' and token.count(u'.') == 0: 105 token = token.replace(u',', u'.') 106 return token 107 108 def __iter__(self): 109 return self 110 111 def __next__(self): 112 token = self.get_token() 113 if token is None: 114 raise StopIteration 115 return token 116 117 def next(self): 118 return self.__next__() 119 120 @classmethod 121 def split(cls, s): 122 return list(cls(s)) 123 124 @classmethod 125 def isword(cls, nextchar): 126 return nextchar.isalpha() 127 128 @classmethod 129 def isnum(cls, nextchar): 130 return nextchar.isdigit() 131 132 @classmethod 133 def isspace(cls, nextchar): 134 return nextchar.isspace() 135 136 137 class _resultbase(object): 138 139 def __init__(self): 140 for attr in self.__slots__: 141 setattr(self, attr, None) 142 143 def _repr(self, classname): 144 l = [] 145 for attr in self.__slots__: 146 value = getattr(self, attr) 147 if value is not None: 148 l.append(u'%s=%s' % (attr, repr(value))) 149 150 return u'%s(%s)' % (classname, u', '.join(l)) 151 152 def __len__(self): 153 return sum((getattr(self, attr) is not None for attr in self.__slots__)) 154 155 def __repr__(self): 156 return self._repr(self.__class__.__name__) 157 158 159 class parserinfo(object): 160 JUMP = [u' ', 161 u'.', 162 u',', 163 u';', 164 u'-', 165 u'/', 166 u"'", 167 u'at', 168 u'on', 169 u'and', 170 u'ad', 171 u'm', 172 u't', 173 u'of', 174 u'st', 175 u'nd', 176 u'rd', 177 u'th'] 178 WEEKDAYS = [(u'Mon', u'Monday'), 179 (u'Tue', u'Tuesday'), 180 (u'Wed', u'Wednesday'), 181 (u'Thu', u'Thursday'), 182 (u'Fri', u'Friday'), 183 (u'Sat', u'Saturday'), 184 (u'Sun', u'Sunday')] 185 MONTHS = [(u'Jan', u'January'), 186 (u'Feb', u'February'), 187 (u'Mar', u'March'), 188 (u'Apr', u'April'), 189 (u'May', u'May'), 190 (u'Jun', u'June'), 191 (u'Jul', u'July'), 192 (u'Aug', u'August'), 193 (u'Sep', u'Sept', u'September'), 194 (u'Oct', u'October'), 195 (u'Nov', u'November'), 196 (u'Dec', u'December')] 197 HMS = [(u'h', u'hour', u'hours'), (u'm', u'minute', u'minutes'), (u's', u'second', u'seconds')] 198 AMPM = [(u'am', u'a'), (u'pm', u'p')] 199 UTCZONE = [u'UTC', u'GMT', u'Z'] 200 PERTAIN = [u'of'] 201 TZOFFSET = {} 202 203 def __init__(self, dayfirst = False, yearfirst = False): 204 self._jump = self._convert(self.JUMP) 205 self._weekdays = self._convert(self.WEEKDAYS) 206 self._months = self._convert(self.MONTHS) 207 self._hms = self._convert(self.HMS) 208 self._ampm = self._convert(self.AMPM) 209 self._utczone = self._convert(self.UTCZONE) 210 self._pertain = self._convert(self.PERTAIN) 211 self.dayfirst = dayfirst 212 self.yearfirst = yearfirst 213 self._year = time.localtime().tm_year 214 self._century = self._year // 100 * 100 215 216 def _convert(self, lst): 217 dct = {} 218 for i, v in enumerate(lst): 219 if isinstance(v, tuple): 220 for v in v: 221 dct[v.lower()] = i 222 223 else: 224 dct[v.lower()] = i 225 226 return dct 227 228 def jump(self, name): 229 return name.lower() in self._jump 230 231 def weekday(self, name): 232 if len(name) >= 3: 233 try: 234 return self._weekdays[name.lower()] 235 except KeyError: 236 pass 237 238 def month(self, name): 239 if len(name) >= 3: 240 try: 241 return self._months[name.lower()] + 1 242 except KeyError: 243 pass 244 245 def hms(self, name): 246 try: 247 return self._hms[name.lower()] 248 except KeyError: 249 return None 250 251 def ampm(self, name): 252 try: 253 return self._ampm[name.lower()] 254 except KeyError: 255 return None 256 257 def pertain(self, name): 258 return name.lower() in self._pertain 259 260 def utczone(self, name): 261 return name.lower() in self._utczone 262 263 def tzoffset(self, name): 264 if name in self._utczone: 265 return 0 266 return self.TZOFFSET.get(name) 267 268 def convertyear(self, year, century_specified = False): 269 if year < 100 and not century_specified: 270 year += self._century 271 if abs(year - self._year) >= 50: 272 if year < self._year: 273 year += 100 274 else: 275 year -= 100 276 return year 277 278 def validate(self, res): 279 if res.year is not None: 280 res.year = self.convertyear(res.year, res.century_specified) 281 if res.tzoffset == 0 and not res.tzname or res.tzname == u'Z': 282 res.tzname = u'UTC' 283 res.tzoffset = 0 284 elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname): 285 res.tzoffset = 0 286 return True 287 288 289 class _ymd(list): 290 291 def __init__(self, tzstr, *args, **kwargs): 292 super(self.__class__, self).__init__(*args, **kwargs) 293 self.century_specified = False 294 self.tzstr = tzstr 295 296 @staticmethod 297 def token_could_be_year(token, year): 298 try: 299 return int(token) == year 300 except ValueError: 301 return False 302 303 @staticmethod 304 def find_potential_year_tokens(year, tokens): 305 return [ token for token in tokens if _ymd.token_could_be_year(token, year) ] 306 307 def find_probable_year_index(self, tokens): 308 for index, token in enumerate(self): 309 potential_year_tokens = _ymd.find_potential_year_tokens(token, tokens) 310 if len(potential_year_tokens) == 1 and len(potential_year_tokens[0]) > 2: 311 return index 312 313 def append(self, val): 314 if hasattr(val, u'__len__'): 315 if val.isdigit() and len(val) > 2: 316 self.century_specified = True 317 elif val > 100: 318 self.century_specified = True 319 super(self.__class__, self).append(int(val)) 320 321 def resolve_ymd(self, mstridx, yearfirst, dayfirst): 322 len_ymd = len(self) 323 year, month, day = (None, None, None) 324 if len_ymd > 3: 325 raise ValueError(u'More than three YMD values') 326 elif len_ymd == 1 or mstridx != -1 and len_ymd == 2: 327 if mstridx != -1: 328 month = self[mstridx] 329 del self[mstridx] 330 if len_ymd > 1 or mstridx == -1: 331 if self[0] > 31: 332 year = self[0] 333 else: 334 day = self[0] 335 elif len_ymd == 2: 336 if self[0] > 31: 337 year, month = self 338 elif self[1] > 31: 339 month, year = self 340 elif dayfirst and self[1] <= 12: 341 day, month = self 342 else: 343 month, day = self 344 elif len_ymd == 3: 345 if mstridx == 0: 346 month, day, year = self 347 elif mstridx == 1: 348 if self[0] > 31 or yearfirst and self[2] <= 31: 349 year, month, day = self 350 else: 351 day, month, year = self 352 elif mstridx == 2: 353 if self[1] > 31: 354 day, year, month = self 355 else: 356 year, day, month = self 357 elif self[0] > 31 or self.find_probable_year_index(_timelex.split(self.tzstr)) == 0 or yearfirst and self[1] <= 12 and self[2] <= 31: 358 if dayfirst and self[2] <= 12: 359 year, day, month = self 360 else: 361 year, month, day = self 362 elif self[0] > 12 or dayfirst and self[1] <= 12: 363 day, month, year = self 364 else: 365 month, day, year = self 366 return (year, month, day) 367 368 369 class parser(object): 370 371 def __init__(self, info = None): 372 self.info = info or parserinfo() 373 374 def parse(self, timestr, default = None, ignoretz = False, tzinfos = None, **kwargs): 375 if default is None: 376 effective_dt = datetime.datetime.now() 377 default = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) 378 else: 379 effective_dt = default 380 res, skipped_tokens = self._parse(timestr, **kwargs) 381 if res is None: 382 raise ValueError(u'Unknown string format') 383 if len(res) == 0: 384 raise ValueError(u'String does not contain a date.') 385 repl = {} 386 for attr in (u'year', u'month', u'day', u'hour', u'minute', u'second', u'microsecond'): 387 value = getattr(res, attr) 388 if value is not None: 389 repl[attr] = value 390 391 if u'day' not in repl: 392 cyear = default.year if res.year is None else res.year 393 cmonth = default.month if res.month is None else res.month 394 cday = default.day if res.day is None else res.day 395 if cday > monthrange(cyear, cmonth)[1]: 396 repl[u'day'] = monthrange(cyear, cmonth)[1] 397 ret = default.replace(**repl) 398 if res.weekday is not None and not res.day: 399 ret = ret + relativedelta.relativedelta(weekday=res.weekday) 400 if not ignoretz: 401 if isinstance(tzinfos, collections.Callable) or tzinfos and res.tzname in tzinfos: 402 if isinstance(tzinfos, collections.Callable): 403 tzdata = tzinfos(res.tzname, res.tzoffset) 404 else: 405 tzdata = tzinfos.get(res.tzname) 406 if isinstance(tzdata, datetime.tzinfo): 407 tzinfo = tzdata 408 elif isinstance(tzdata, text_type): 409 tzinfo = tz.tzstr(tzdata) 410 elif isinstance(tzdata, integer_types): 411 tzinfo = tz.tzoffset(res.tzname, tzdata) 412 else: 413 raise ValueError(u'Offset must be tzinfo subclass, tz string, or int offset.') 414 ret = ret.replace(tzinfo=tzinfo) 415 elif res.tzname and res.tzname in time.tzname: 416 ret = ret.replace(tzinfo=tz.tzlocal()) 417 elif res.tzoffset == 0: 418 ret = ret.replace(tzinfo=tz.tzutc()) 419 elif res.tzoffset: 420 ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset)) 421 if kwargs.get(u'fuzzy_with_tokens', False): 422 return (ret, skipped_tokens) 423 else: 424 return ret 425 426 class _result(_resultbase): 427 __slots__ = [u'year', 428 u'month', 429 u'day', 430 u'weekday', 431 u'hour', 432 u'minute', 433 u'second', 434 u'microsecond', 435 u'tzname', 436 u'tzoffset', 437 u'ampm'] 438 439 def _parse(self, timestr, dayfirst = None, yearfirst = None, fuzzy = False, fuzzy_with_tokens = False): 440 if fuzzy_with_tokens: 441 fuzzy = True 442 info = self.info 443 if dayfirst is None: 444 dayfirst = info.dayfirst 445 if yearfirst is None: 446 yearfirst = info.yearfirst 447 res = self._result() 448 l = _timelex.split(timestr) 449 last_skipped_token_i = -2 450 skipped_tokens = list() 451 try: 452 ymd = _ymd(timestr) 453 mstridx = -1 454 len_l = len(l) 455 i = 0 456 while i < len_l: 457 try: 458 value_repr = l[i] 459 value = float(value_repr) 460 except ValueError: 461 value = None 462 463 if value is not None: 464 len_li = len(l[i]) 465 i += 1 466 if len(ymd) == 3 and len_li in (2, 4) and res.hour is None and (i >= len_l or l[i] != u':' and info.hms(l[i]) is None): 467 s = l[i - 1] 468 res.hour = int(s[:2]) 469 if len_li == 4: 470 res.minute = int(s[2:]) 471 elif len_li == 6 or len_li > 6 and l[i - 1].find(u'.') == 6: 472 s = l[i - 1] 473 if not ymd and l[i - 1].find(u'.') == -1: 474 ymd.append(s[:2]) 475 ymd.append(s[2:4]) 476 ymd.append(s[4:]) 477 else: 478 res.hour = int(s[:2]) 479 res.minute = int(s[2:4]) 480 res.second, res.microsecond = _parsems(s[4:]) 481 elif len_li in (8, 12, 14): 482 s = l[i - 1] 483 ymd.append(s[:4]) 484 ymd.append(s[4:6]) 485 ymd.append(s[6:8]) 486 if len_li > 8: 487 res.hour = int(s[8:10]) 488 res.minute = int(s[10:12]) 489 if len_li > 12: 490 res.second = int(s[12:]) 491 elif i < len_l and info.hms(l[i]) is not None or i + 1 < len_l and l[i] == u' ' and info.hms(l[i + 1]) is not None: 492 if l[i] == u' ': 493 i += 1 494 idx = info.hms(l[i]) 495 while True: 496 if idx == 0: 497 res.hour = int(value) 498 if value % 1: 499 res.minute = int(60 * (value % 1)) 500 elif idx == 1: 501 res.minute = int(value) 502 if value % 1: 503 res.second = int(60 * (value % 1)) 504 elif idx == 2: 505 res.second, res.microsecond = _parsems(value_repr) 506 i += 1 507 if i >= len_l or idx == 2: 508 break 509 try: 510 value_repr = l[i] 511 value = float(value_repr) 512 except ValueError: 513 break 514 else: 515 i += 1 516 idx += 1 517 if i < len_l: 518 newidx = info.hms(l[i]) 519 if newidx is not None: 520 idx = newidx 521 522 elif i == len_l and l[i - 2] == u' ' and info.hms(l[i - 3]) is not None: 523 idx = info.hms(l[i - 3]) + 1 524 if idx == 1: 525 res.minute = int(value) 526 if value % 1: 527 res.second = int(60 * (value % 1)) 528 elif idx == 2: 529 res.second, res.microsecond = _parsems(value_repr) 530 i += 1 531 elif i + 1 < len_l and l[i] == u':': 532 res.hour = int(value) 533 i += 1 534 value = float(l[i]) 535 res.minute = int(value) 536 if value % 1: 537 res.second = int(60 * (value % 1)) 538 i += 1 539 if i < len_l and l[i] == u':': 540 res.second, res.microsecond = _parsems(l[i + 1]) 541 i += 2 542 elif i < len_l and l[i] in (u'-', u'/', u'.'): 543 sep = l[i] 544 ymd.append(value_repr) 545 i += 1 546 if i < len_l and not info.jump(l[i]): 547 try: 548 ymd.append(l[i]) 549 except ValueError: 550 value = info.month(l[i]) 551 if value is not None: 552 ymd.append(value) 553 mstridx = len(ymd) - 1 554 else: 555 return (None, None) 556 557 i += 1 558 if i < len_l and l[i] == sep: 559 i += 1 560 value = info.month(l[i]) 561 if value is not None: 562 ymd.append(value) 563 mstridx = len(ymd) - 1 564 else: 565 ymd.append(l[i]) 566 i += 1 567 elif i >= len_l or info.jump(l[i]): 568 if i + 1 < len_l and info.ampm(l[i + 1]) is not None: 569 res.hour = int(value) 570 if res.hour < 12 and info.ampm(l[i + 1]) == 1: 571 res.hour += 12 572 elif res.hour == 12 and info.ampm(l[i + 1]) == 0: 573 res.hour = 0 574 i += 1 575 else: 576 ymd.append(value) 577 i += 1 578 elif info.ampm(l[i]) is not None: 579 res.hour = int(value) 580 if res.hour < 12 and info.ampm(l[i]) == 1: 581 res.hour += 12 582 elif res.hour == 12 and info.ampm(l[i]) == 0: 583 res.hour = 0 584 i += 1 585 else: 586 if not fuzzy: 587 return (None, None) 588 i += 1 589 continue 590 value = info.weekday(l[i]) 591 if value is not None: 592 res.weekday = value 593 i += 1 594 continue 595 value = info.month(l[i]) 596 if value is not None: 597 ymd.append(value) 598 mstridx = len(ymd) - 1 599 i += 1 600 if i < len_l: 601 if l[i] in (u'-', u'/'): 602 sep = l[i] 603 i += 1 604 ymd.append(l[i]) 605 i += 1 606 if i < len_l and l[i] == sep: 607 i += 1 608 ymd.append(l[i]) 609 i += 1 610 elif i + 3 < len_l and l[i] == l[i + 2] == u' ' and info.pertain(l[i + 1]): 611 try: 612 value = int(l[i + 3]) 613 except ValueError: 614 pass 615 else: 616 ymd.append(str(info.convertyear(value))) 617 618 i += 4 619 continue 620 value = info.ampm(l[i]) 621 if value is not None: 622 val_is_ampm = True 623 if fuzzy and res.ampm is not None: 624 val_is_ampm = False 625 if res.hour is None: 626 if fuzzy: 627 val_is_ampm = False 628 else: 629 raise ValueError(u'No hour specified with ' + u'AM or PM flag.') 630 elif not 0 <= res.hour <= 12: 631 if fuzzy: 632 val_is_ampm = False 633 else: 634 raise ValueError(u'Invalid hour specified for ' + u'12-hour clock.') 635 if val_is_ampm: 636 if value == 1 and res.hour < 12: 637 res.hour += 12 638 elif value == 0 and res.hour == 12: 639 res.hour = 0 640 res.ampm = value 641 i += 1 642 continue 643 if res.hour is not None and len(l[i]) <= 5 and res.tzname is None and res.tzoffset is None and not [ x for x in l[i] if x not in string.ascii_uppercase ]: 644 res.tzname = l[i] 645 res.tzoffset = info.tzoffset(res.tzname) 646 i += 1 647 if i < len_l and l[i] in (u'+', u'-'): 648 l[i] = (u'+', u'-')[l[i] == u'+'] 649 res.tzoffset = None 650 if info.utczone(res.tzname): 651 res.tzname = None 652 continue 653 if res.hour is not None and l[i] in (u'+', u'-'): 654 signal = (-1, 1)[l[i] == u'+'] 655 i += 1 656 len_li = len(l[i]) 657 if len_li == 4: 658 res.tzoffset = int(l[i][:2]) * 3600 + int(l[i][2:]) * 60 659 elif i + 1 < len_l and l[i + 1] == u':': 660 res.tzoffset = int(l[i]) * 3600 + int(l[i + 2]) * 60 661 i += 2 662 elif len_li <= 2: 663 res.tzoffset = int(l[i][:2]) * 3600 664 else: 665 return (None, None) 666 i += 1 667 res.tzoffset *= signal 668 if i + 3 < len_l and info.jump(l[i]) and l[i + 1] == u'(' and l[i + 3] == u')' and 3 <= len(l[i + 2]) <= 5 and not [ x for x in l[i + 2] if x not in string.ascii_uppercase ]: 669 res.tzname = l[i + 2] 670 i += 4 671 continue 672 if not (info.jump(l[i]) or fuzzy): 673 return (None, None) 674 if last_skipped_token_i == i - 1: 675 skipped_tokens[-1] += l[i] 676 else: 677 skipped_tokens.append(l[i]) 678 last_skipped_token_i = i 679 i += 1 680 681 year, month, day = ymd.resolve_ymd(mstridx, yearfirst, dayfirst) 682 if year is not None: 683 res.year = year 684 res.century_specified = ymd.century_specified 685 if month is not None: 686 res.month = month 687 if day is not None: 688 res.day = day 689 except (IndexError, ValueError, AssertionError): 690 return (None, None) 691 692 if not info.validate(res): 693 return (None, None) 694 elif fuzzy_with_tokens: 695 return (res, tuple(skipped_tokens)) 696 else: 697 return (res, None) 698 699 700 DEFAULTPARSER = parser() 701 702 def parse(timestr, parserinfo = None, **kwargs): 703 if parserinfo: 704 return parser(parserinfo).parse(timestr, **kwargs) 705 else: 706 return DEFAULTPARSER.parse(timestr, **kwargs) 707 708 709 class _tzparser(object): 710 711 class _result(_resultbase): 712 __slots__ = [u'stdabbr', 713 u'stdoffset', 714 u'dstabbr', 715 u'dstoffset', 716 u'start', 717 u'end'] 718 719 class _attr(_resultbase): 720 __slots__ = [u'month', 721 u'week', 722 u'weekday', 723 u'yday', 724 u'jyday', 725 u'day', 726 u'time'] 727 728 def __repr__(self): 729 return self._repr(u'') 730 731 def __init__(self): 732 _resultbase.__init__(self) 733 self.start = self._attr() 734 self.end = self._attr() 735 736 def parse(self, tzstr): 737 res = self._result() 738 l = _timelex.split(tzstr) 739 try: 740 len_l = len(l) 741 i = 0 742 while i < len_l: 743 j = i 744 while j < len_l and not [ x for x in l[j] if x in u'0123456789:,-+' ]: 745 j += 1 746 747 if j != i: 748 if not res.stdabbr: 749 offattr = u'stdoffset' 750 res.stdabbr = u''.join(l[i:j]) 751 else: 752 offattr = u'dstoffset' 753 res.dstabbr = u''.join(l[i:j]) 754 i = j 755 if i < len_l and (l[i] in (u'+', u'-') or l[i][0] in u'0123456789'): 756 if l[i] in (u'+', u'-'): 757 signal = (1, -1)[l[i] == u'+'] 758 i += 1 759 else: 760 signal = -1 761 len_li = len(l[i]) 762 if len_li == 4: 763 setattr(res, offattr, (int(l[i][:2]) * 3600 + int(l[i][2:]) * 60) * signal) 764 elif i + 1 < len_l and l[i + 1] == u':': 765 setattr(res, offattr, (int(l[i]) * 3600 + int(l[i + 2]) * 60) * signal) 766 i += 2 767 elif len_li <= 2: 768 setattr(res, offattr, int(l[i][:2]) * 3600 * signal) 769 else: 770 return None 771 i += 1 772 if res.dstabbr: 773 break 774 else: 775 break 776 777 if i < len_l: 778 for j in range(i, len_l): 779 if l[j] == u';': 780 l[j] = u',' 781 782 i += 1 783 if i >= len_l: 784 pass 785 elif 8 <= l.count(u',') <= 9 and not [ y for x in l[i:] if x != u',' for y in x if y not in u'0123456789' ]: 786 for x in (res.start, res.end): 787 x.month = int(l[i]) 788 i += 2 789 if l[i] == u'-': 790 value = int(l[i + 1]) * -1 791 i += 1 792 else: 793 value = int(l[i]) 794 i += 2 795 if value: 796 x.week = value 797 x.weekday = (int(l[i]) - 1) % 7 798 else: 799 x.day = int(l[i]) 800 i += 2 801 x.time = int(l[i]) 802 i += 2 803 804 if i < len_l: 805 if l[i] in (u'-', u'+'): 806 signal = (-1, 1)[l[i] == u'+'] 807 i += 1 808 else: 809 signal = 1 810 res.dstoffset = (res.stdoffset + int(l[i])) * signal 811 elif l.count(u',') == 2 and l[i:].count(u'/') <= 2 and not [ y for x in l[i:] if x not in (u',', u'/', u'J', u'M', u'.', u'-', u':') for y in x if y not in u'0123456789' ]: 812 for x in (res.start, res.end): 813 if l[i] == u'J': 814 i += 1 815 x.jyday = int(l[i]) 816 elif l[i] == u'M': 817 i += 1 818 x.month = int(l[i]) 819 i += 1 820 i += 1 821 x.week = int(l[i]) 822 if x.week == 5: 823 x.week = -1 824 i += 1 825 i += 1 826 x.weekday = (int(l[i]) - 1) % 7 827 else: 828 x.yday = int(l[i]) + 1 829 i += 1 830 if i < len_l and l[i] == u'/': 831 i += 1 832 len_li = len(l[i]) 833 if len_li == 4: 834 x.time = int(l[i][:2]) * 3600 + int(l[i][2:]) * 60 835 elif i + 1 < len_l and l[i + 1] == u':': 836 x.time = int(l[i]) * 3600 + int(l[i + 2]) * 60 837 i += 2 838 if i + 1 < len_l and l[i + 1] == u':': 839 i += 2 840 x.time += int(l[i]) 841 elif len_li <= 2: 842 x.time = int(l[i][:2]) * 3600 843 else: 844 return None 845 i += 1 846 i += 1 847 848 except (IndexError, ValueError, AssertionError): 849 return None 850 851 return res 852 853 854 DEFAULTTZPARSER = _tzparser() 855 856 def _parsetz(tzstr): 857 return DEFAULTTZPARSER.parse(tzstr) 858 859 860 def _parsems(value): 861 if u'.' not in value: 862 return (int(value), 0) 863 else: 864 i, f = value.split(u'.') 865 return (int(i), int(f.ljust(6, u'0')[:6]))