14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""Strptime-related classes and functions.
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
34adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoCLASSES:
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    LocaleTime -- Discovers and stores locale-specific time information
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    TimeRE -- Creates regexes for pattern matching a string of text containing
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                time information
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
84adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoFUNCTIONS:
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    _getlang -- Figure out what language is being used for the locale
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    strptime -- Calculates the time struct represented by the passed-in string
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport time
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport locale
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport calendar
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom re import compile as re_compile
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom re import IGNORECASE
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom re import escape as re_escape
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom datetime import date as datetime_date
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaotry:
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    from thread import allocate_lock as _thread_allocate_lock
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoexcept:
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    from dummy_thread import allocate_lock as _thread_allocate_lock
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao__all__ = []
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _getlang():
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # Figure out what the current language is set to.
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return locale.getlocale(locale.LC_TIME)
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass LocaleTime(object):
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Stores and handles locale-specific information related to time.
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    ATTRIBUTES:
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        f_weekday -- full weekday names (7-item list)
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        a_weekday -- abbreviated weekday names (7-item list)
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        f_month -- full month names (13-item list; dummy value in [0], which
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    is added by code)
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        a_month -- abbreviated month names (13-item list, dummy value in
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    [0], which is added by code)
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        am_pm -- AM/PM representation (2-item list)
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        LC_date_time -- format string for date/time representation (string)
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        LC_date -- format string for date representation (string)
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        LC_time -- format string for time representation (string)
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        timezone -- daylight- and non-daylight-savings timezone representation
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    (2-item list of sets)
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        lang -- Language used by instance (2-item tuple)
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self):
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """Set all attributes.
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Order of methods called matters for dependency reasons.
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        The locale language is set at the offset and then checked again before
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        exiting.  This is to make sure that the attributes were not set with a
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        mix of information from more than one locale.  This would most likely
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        happen when using threads where one thread calls a locale-dependent
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        function while another thread changes the locale while the function in
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        the other thread is still running.  Proper coding would call for
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        locks to prevent changing the locale while locale-dependent code is
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        running.  The check here is done in case someone does not think about
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        doing this.
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Only other possible issue is if someone changed the timezone and did
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        not call tz.tzset .  That is an issue for the programmer, though,
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        since changing the timezone is worthless without that call.
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.lang = _getlang()
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__calc_weekday()
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__calc_month()
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__calc_am_pm()
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__calc_timezone()
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.__calc_date_time()
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if _getlang() != self.lang:
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise ValueError("locale changed during initialization")
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __pad(self, seq, front):
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Add '' to seq to either the front (is True), else the back.
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        seq = list(seq)
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if front:
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            seq.insert(0, '')
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            seq.append('')
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return seq
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __calc_weekday(self):
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Set self.a_weekday and self.f_weekday using the calendar
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # module.
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        a_weekday = [calendar.day_abbr[i].lower() for i in range(7)]
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        f_weekday = [calendar.day_name[i].lower() for i in range(7)]
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.a_weekday = a_weekday
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.f_weekday = f_weekday
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __calc_month(self):
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Set self.f_month and self.a_month using the calendar module.
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        a_month = [calendar.month_abbr[i].lower() for i in range(13)]
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        f_month = [calendar.month_name[i].lower() for i in range(13)]
1004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.a_month = a_month
1014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.f_month = f_month
1024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __calc_am_pm(self):
1044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Set self.am_pm by using time.strftime().
1054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # The magic date (1999,3,17,hour,44,55,2,76,0) is not really that
1074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # magical; just happened to have used it everywhere else where a
1084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # static date was needed.
1094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        am_pm = []
1104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for hour in (01,22):
1114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            time_tuple = time.struct_time((1999,3,17,hour,44,55,2,76,0))
1124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            am_pm.append(time.strftime("%p", time_tuple).lower())
1134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.am_pm = am_pm
1144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __calc_date_time(self):
1164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Set self.date_time, self.date, & self.time by using
1174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # time.strftime().
1184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Use (1999,3,17,22,44,55,2,76,0) for magic date because the amount of
1204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # overloaded numbers is minimized.  The order in which searches for
1214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # values within the format string is very important; it eliminates
1224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # possible ambiguity for what something represents.
1234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0))
1244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        date_time = [None, None, None]
1254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        date_time[0] = time.strftime("%c", time_tuple).lower()
1264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        date_time[1] = time.strftime("%x", time_tuple).lower()
1274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        date_time[2] = time.strftime("%X", time_tuple).lower()
1284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        replacement_pairs = [('%', '%%'), (self.f_weekday[2], '%A'),
1294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    (self.f_month[3], '%B'), (self.a_weekday[2], '%a'),
1304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    (self.a_month[3], '%b'), (self.am_pm[1], '%p'),
1314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    ('1999', '%Y'), ('99', '%y'), ('22', '%H'),
1324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    ('44', '%M'), ('55', '%S'), ('76', '%j'),
1334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    ('17', '%d'), ('03', '%m'), ('3', '%m'),
1344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    # '3' needed for when no leading zero.
1354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    ('2', '%w'), ('10', '%I')]
1364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        replacement_pairs.extend([(tz, "%Z") for tz_values in self.timezone
1374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                                for tz in tz_values])
1384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for offset,directive in ((0,'%c'), (1,'%x'), (2,'%X')):
1394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            current_format = date_time[offset]
1404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            for old, new in replacement_pairs:
1414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # Must deal with possible lack of locale info
1424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # manifesting itself as the empty string (e.g., Swedish's
1434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # lack of AM/PM info) or a platform returning a tuple of empty
1444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # strings (e.g., MacOS 9 having timezone as ('','')).
1454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                if old:
1464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    current_format = current_format.replace(old, new)
1474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # If %W is used, then Sunday, 2005-01-03 will fall on week 0 since
1484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # 2005-01-03 occurs before the first Monday of the year.  Otherwise
1494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # %U is used.
1504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0))
1514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if '00' in time.strftime(directive, time_tuple):
1524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                U_W = '%W'
1534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            else:
1544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                U_W = '%U'
1554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            date_time[offset] = current_format.replace('11', U_W)
1564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.LC_date_time = date_time[0]
1574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.LC_date = date_time[1]
1584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.LC_time = date_time[2]
1594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __calc_timezone(self):
1614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Set self.timezone by using time.tzname.
1624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Do not worry about possibility of time.tzname[0] == timetzname[1]
1634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # and time.daylight; handle that in strptime .
1644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
1654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            time.tzset()
1664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except AttributeError:
1674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            pass
1684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        no_saving = frozenset(["utc", "gmt", time.tzname[0].lower()])
1694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if time.daylight:
1704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            has_saving = frozenset([time.tzname[1].lower()])
1714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
1724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            has_saving = frozenset()
1734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.timezone = (no_saving, has_saving)
1744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass TimeRE(dict):
1774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Handle conversion from format directives to regexes."""
1784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, locale_time=None):
1804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """Create keys/values.
1814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Order of execution is important for dependency reasons.
1834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """
1854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if locale_time:
1864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.locale_time = locale_time
1874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
1884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.locale_time = LocaleTime()
1894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base = super(TimeRE, self)
1904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base.__init__({
1914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # The " \d" part of the regex is to make %c from ANSI C work
1924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'd': r"(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])",
1934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'f': r"(?P<f>[0-9]{1,6})",
1944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'H': r"(?P<H>2[0-3]|[0-1]\d|\d)",
1954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'I': r"(?P<I>1[0-2]|0[1-9]|[1-9])",
1964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'j': r"(?P<j>36[0-6]|3[0-5]\d|[1-2]\d\d|0[1-9]\d|00[1-9]|[1-9]\d|0[1-9]|[1-9])",
1974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'm': r"(?P<m>1[0-2]|0[1-9]|[1-9])",
1984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'M': r"(?P<M>[0-5]\d|\d)",
1994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'S': r"(?P<S>6[0-1]|[0-5]\d|\d)",
2004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'U': r"(?P<U>5[0-3]|[0-4]\d|\d)",
2014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'w': r"(?P<w>[0-6])",
2024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # W is set below by using 'U'
2034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'y': r"(?P<y>\d\d)",
2044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            #XXX: Does 'Y' need to worry about having less or more than
2054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            #     4 digits?
2064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'Y': r"(?P<Y>\d\d\d\d)",
2074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'A': self.__seqToRE(self.locale_time.f_weekday, 'A'),
2084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'a': self.__seqToRE(self.locale_time.a_weekday, 'a'),
2094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'),
2104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'b': self.__seqToRE(self.locale_time.a_month[1:], 'b'),
2114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'p': self.__seqToRE(self.locale_time.am_pm, 'p'),
2124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone
2134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                        for tz in tz_names),
2144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                'Z'),
2154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            '%': '%'})
2164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base.__setitem__('W', base.__getitem__('U').replace('U', 'W'))
2174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base.__setitem__('c', self.pattern(self.locale_time.LC_date_time))
2184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base.__setitem__('x', self.pattern(self.locale_time.LC_date))
2194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base.__setitem__('X', self.pattern(self.locale_time.LC_time))
2204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __seqToRE(self, to_convert, directive):
2224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """Convert a list to a regex string for matching a directive.
2234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Want possible matching values to be from longest to shortest.  This
2254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        prevents the possibility of a match occuring for a value that also
2264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        a substring of a larger value that should have matched (e.g., 'abc'
2274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        matching when 'abcdef' should have been the match).
2284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """
2304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        to_convert = sorted(to_convert, key=len, reverse=True)
2314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for value in to_convert:
2324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if value != '':
2334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                break
2344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
2354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return ''
2364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        regex = '|'.join(re_escape(stuff) for stuff in to_convert)
2374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        regex = '(?P<%s>%s' % (directive, regex)
2384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return '%s)' % regex
2394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def pattern(self, format):
2414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """Return regex pattern for the format string.
2424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        Need to make sure that any characters that might be interpreted as
2444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        regex syntax are escaped.
2454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """
2474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        processed_format = ''
2484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # The sub() call escapes all characters that might be misconstrued
2494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # as regex syntax.  Cannot use re.escape since we have to deal with
2504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # format directives (%m, etc.).
2514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        regex_chars = re_compile(r"([\\.^$*+?\(\){}\[\]|])")
2524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        format = regex_chars.sub(r"\\\1", format)
2534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        whitespace_replacement = re_compile('\s+')
2544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        format = whitespace_replacement.sub('\s+', format)
2554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        while '%' in format:
2564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            directive_index = format.index('%')+1
2574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            processed_format = "%s%s%s" % (processed_format,
2584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                           format[:directive_index-1],
2594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                           self[format[directive_index]])
2604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            format = format[directive_index+1:]
2614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return "%s%s" % (processed_format, format)
2624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def compile(self, format):
2644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """Return a compiled re object for the format string."""
2654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return re_compile(self.pattern(format), IGNORECASE)
2664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao_cache_lock = _thread_allocate_lock()
2684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# DO NOT modify _TimeRE_cache or _regex_cache without acquiring the cache lock
2694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# first!
2704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao_TimeRE_cache = TimeRE()
2714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao_CACHE_MAX_SIZE = 5 # Max number of regexes stored in _regex_cache
2724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao_regex_cache = {}
2734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _calc_julian_from_U_or_W(year, week_of_year, day_of_week, week_starts_Mon):
2754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Calculate the Julian day based on the year, week of the year, and day of
2764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    the week, with week_start_day representing whether the week of the year
2774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    assumes the week starts on Sunday or Monday (6 or 0)."""
2784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    first_weekday = datetime_date(year, 1, 1).weekday()
2794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # If we are dealing with the %U directive (week starts on Sunday), it's
2804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # easier to just shift the view to Sunday being the first day of the
2814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # week.
2824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if not week_starts_Mon:
2834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        first_weekday = (first_weekday + 1) % 7
2844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        day_of_week = (day_of_week + 1) % 7
2854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # Need to watch out for a week 0 (when the first day of the year is not
2864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # the same as that specified by %U or %W).
2874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    week_0_length = (7 - first_weekday) % 7
2884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if week_of_year == 0:
2894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 1 + day_of_week - first_weekday
2904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:
2914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        days_to_week = week_0_length + (7 * (week_of_year - 1))
2924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 1 + days_to_week + day_of_week
2934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
2964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Return a time struct based on the input string and the format string."""
2974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    global _TimeRE_cache, _regex_cache
2984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    with _cache_lock:
2994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if _getlang() != _TimeRE_cache.locale_time.lang:
3004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            _TimeRE_cache = TimeRE()
3014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            _regex_cache.clear()
3024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if len(_regex_cache) > _CACHE_MAX_SIZE:
3034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            _regex_cache.clear()
3044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        locale_time = _TimeRE_cache.locale_time
3054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        format_regex = _regex_cache.get(format)
3064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if not format_regex:
3074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            try:
3084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                format_regex = _TimeRE_cache.compile(format)
3094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # KeyError raised when a bad format is found; can be specified as
3104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # \\, in which case it was a stray % but with a space after it
3114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            except KeyError, err:
3124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                bad_directive = err.args[0]
3134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                if bad_directive == "\\":
3144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    bad_directive = "%"
3154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                del err
3164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                raise ValueError("'%s' is a bad directive in format '%s'" %
3174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                    (bad_directive, format))
3184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # IndexError only occurs when the format string is "%"
3194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            except IndexError:
3204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                raise ValueError("stray %% in format '%s'" % format)
3214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            _regex_cache[format] = format_regex
3224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    found = format_regex.match(data_string)
3234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if not found:
3244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise ValueError("time data %r does not match format %r" %
3254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                         (data_string, format))
3264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if len(data_string) != found.end():
3274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise ValueError("unconverted data remains: %s" %
3284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                          data_string[found.end():])
3294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    year = None
3314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    month = day = 1
3324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    hour = minute = second = fraction = 0
3334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    tz = -1
3344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # Default to -1 to signify that values not known; not critical to have,
3354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # though
3364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    week_of_year = -1
3374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    week_of_year_start = -1
3384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # weekday and julian defaulted to -1 so as to signal need to calculate
3394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # values
3404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    weekday = julian = -1
3414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    found_dict = found.groupdict()
3424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    for group_key in found_dict.iterkeys():
3434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Directives not explicitly handled below:
3444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        #   c, x, X
3454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        #      handled by making out of other directives
3464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        #   U, W
3474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        #      worthless without day of the week
3484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if group_key == 'y':
3494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            year = int(found_dict['y'])
3504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # Open Group specification for strptime() states that a %y
3514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            #value in the range of [00, 68] is in the century 2000, while
3524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            #[69,99] is in the century 1900
3534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if year <= 68:
3544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                year += 2000
3554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            else:
3564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                year += 1900
3574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'Y':
3584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            year = int(found_dict['Y'])
3594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'm':
3604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            month = int(found_dict['m'])
3614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'B':
3624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            month = locale_time.f_month.index(found_dict['B'].lower())
3634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'b':
3644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            month = locale_time.a_month.index(found_dict['b'].lower())
3654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'd':
3664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            day = int(found_dict['d'])
3674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'H':
3684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            hour = int(found_dict['H'])
3694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'I':
3704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            hour = int(found_dict['I'])
3714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ampm = found_dict.get('p', '').lower()
3724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # If there was no AM/PM indicator, we'll treat this like AM
3734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if ampm in ('', locale_time.am_pm[0]):
3744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # We're in AM so the hour is correct unless we're
3754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # looking at 12 midnight.
3764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # 12 midnight == 12 AM == hour 0
3774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                if hour == 12:
3784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    hour = 0
3794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            elif ampm == locale_time.am_pm[1]:
3804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # We're in PM so we need to add 12 to the hour unless
3814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # we're looking at 12 noon.
3824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # 12 noon == 12 PM == hour 12
3834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                if hour != 12:
3844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    hour += 12
3854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'M':
3864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            minute = int(found_dict['M'])
3874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'S':
3884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            second = int(found_dict['S'])
3894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'f':
3904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s = found_dict['f']
3914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # Pad to always return microseconds.
3924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            s += "0" * (6 - len(s))
3934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            fraction = int(s)
3944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'A':
3954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            weekday = locale_time.f_weekday.index(found_dict['A'].lower())
3964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'a':
3974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            weekday = locale_time.a_weekday.index(found_dict['a'].lower())
3984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'w':
3994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            weekday = int(found_dict['w'])
4004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if weekday == 0:
4014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                weekday = 6
4024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            else:
4034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                weekday -= 1
4044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'j':
4054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            julian = int(found_dict['j'])
4064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key in ('U', 'W'):
4074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            week_of_year = int(found_dict[group_key])
4084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            if group_key == 'U':
4094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # U starts week on Sunday.
4104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                week_of_year_start = 6
4114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            else:
4124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                # W starts week on Monday.
4134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                week_of_year_start = 0
4144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        elif group_key == 'Z':
4154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # Since -1 is default value only need to worry about setting tz if
4164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # it can be something other than -1.
4174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            found_zone = found_dict['Z'].lower()
4184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            for value, tz_values in enumerate(locale_time.timezone):
4194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                if found_zone in tz_values:
4204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    # Deal with bad locale setup where timezone names are the
4214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    # same and yet time.daylight is true; too ambiguous to
4224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    # be able to tell what timezone has daylight savings
4234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    if (time.tzname[0] == time.tzname[1] and
4244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                       time.daylight and found_zone not in ("utc", "gmt")):
4254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                        break
4264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    else:
4274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                        tz = value
4284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                        break
4294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    leap_year_fix = False
4304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if year is None and month == 2 and day == 29:
4314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        year = 1904  # 1904 is first leap year of 20th century
4324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        leap_year_fix = True
4334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    elif year is None:
4344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        year = 1900
4354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # If we know the week of the year and what day of that week, we can figure
4364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # out the Julian day of the year.
4374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if julian == -1 and week_of_year != -1 and weekday != -1:
4384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        week_starts_Mon = True if week_of_year_start == 0 else False
4394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        julian = _calc_julian_from_U_or_W(year, week_of_year, weekday,
4404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                            week_starts_Mon)
4414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # Cannot pre-calculate datetime_date() since can change in Julian
4424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # calculation and thus could have different value for the day of the week
4434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # calculation.
4444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if julian == -1:
4454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Need to add 1 to result since first day of the year is 1, not 0.
4464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        julian = datetime_date(year, month, day).toordinal() - \
4474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                  datetime_date(year, 1, 1).toordinal() + 1
4484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:  # Assume that if they bothered to include Julian day it will
4494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao           # be accurate.
4504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        datetime_result = datetime_date.fromordinal((julian - 1) + datetime_date(year, 1, 1).toordinal())
4514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        year = datetime_result.year
4524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        month = datetime_result.month
4534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        day = datetime_result.day
4544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if weekday == -1:
4554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        weekday = datetime_date(year, month, day).weekday()
4564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if leap_year_fix:
4574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # the caller didn't supply a year but asked for Feb 29th. We couldn't
4584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # use the default of 1900 for computations. We set it back to ensure
4594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # that February 29th is smaller than March 1st.
4604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        year = 1900
4614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return (time.struct_time((year, month, day,
4634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                              hour, minute, second,
4644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                              weekday, julian, tz)), fraction)
4654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
4664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef _strptime_time(data_string, format="%a %b %d %H:%M:%S %Y"):
4674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return _strptime(data_string, format)[0]
468