NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

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]))