1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""Strptime-related classes and functions. 2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehCLASSES: 4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh LocaleTime -- Discovers and stores locale-specific time information 5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh TimeRE -- Creates regexes for pattern matching a string of text containing 6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time information 7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehFUNCTIONS: 9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh _getlang -- Figure out what language is being used for the locale 10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh strptime -- Calculates the time struct represented by the passed-in string 11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh""" 13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport time 14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport locale 15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport calendar 16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom re import compile as re_compile 17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom re import IGNORECASE 18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom re import escape as re_escape 19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom datetime import date as datetime_date 20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehtry: 21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh from thread import allocate_lock as _thread_allocate_lock 22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehexcept: 23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh from dummy_thread import allocate_lock as _thread_allocate_lock 24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh__all__ = [] 26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef _getlang(): 28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Figure out what the current language is set to. 29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return locale.getlocale(locale.LC_TIME) 30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass LocaleTime(object): 32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Stores and handles locale-specific information related to time. 33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ATTRIBUTES: 35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh f_weekday -- full weekday names (7-item list) 36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh a_weekday -- abbreviated weekday names (7-item list) 37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh f_month -- full month names (13-item list; dummy value in [0], which 38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh is added by code) 39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh a_month -- abbreviated month names (13-item list, dummy value in 40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh [0], which is added by code) 41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh am_pm -- AM/PM representation (2-item list) 42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh LC_date_time -- format string for date/time representation (string) 43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh LC_date -- format string for date representation (string) 44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh LC_time -- format string for time representation (string) 45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh timezone -- daylight- and non-daylight-savings timezone representation 46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh (2-item list of sets) 47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh lang -- Language used by instance (2-item tuple) 48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self): 51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Set all attributes. 52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Order of methods called matters for dependency reasons. 54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh The locale language is set at the offset and then checked again before 56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh exiting. This is to make sure that the attributes were not set with a 57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh mix of information from more than one locale. This would most likely 58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh happen when using threads where one thread calls a locale-dependent 59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh function while another thread changes the locale while the function in 60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh the other thread is still running. Proper coding would call for 61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh locks to prevent changing the locale while locale-dependent code is 62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh running. The check here is done in case someone does not think about 63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh doing this. 64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Only other possible issue is if someone changed the timezone and did 66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh not call tz.tzset . That is an issue for the programmer, though, 67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh since changing the timezone is worthless without that call. 68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.lang = _getlang() 71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.__calc_weekday() 72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.__calc_month() 73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.__calc_am_pm() 74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.__calc_timezone() 75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.__calc_date_time() 76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if _getlang() != self.lang: 77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise ValueError("locale changed during initialization") 78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __pad(self, seq, front): 80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Add '' to seq to either the front (is True), else the back. 81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh seq = list(seq) 82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if front: 83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh seq.insert(0, '') 84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh seq.append('') 86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return seq 87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __calc_weekday(self): 89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Set self.a_weekday and self.f_weekday using the calendar 90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # module. 91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh a_weekday = [calendar.day_abbr[i].lower() for i in range(7)] 92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh f_weekday = [calendar.day_name[i].lower() for i in range(7)] 93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.a_weekday = a_weekday 94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.f_weekday = f_weekday 95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __calc_month(self): 97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Set self.f_month and self.a_month using the calendar module. 98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh a_month = [calendar.month_abbr[i].lower() for i in range(13)] 99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh f_month = [calendar.month_name[i].lower() for i in range(13)] 100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.a_month = a_month 101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.f_month = f_month 102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __calc_am_pm(self): 104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Set self.am_pm by using time.strftime(). 105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # The magic date (1999,3,17,hour,44,55,2,76,0) is not really that 107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # magical; just happened to have used it everywhere else where a 108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # static date was needed. 109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh am_pm = [] 110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for hour in (01,22): 111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time_tuple = time.struct_time((1999,3,17,hour,44,55,2,76,0)) 112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh am_pm.append(time.strftime("%p", time_tuple).lower()) 113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.am_pm = am_pm 114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __calc_date_time(self): 116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Set self.date_time, self.date, & self.time by using 117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # time.strftime(). 118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Use (1999,3,17,22,44,55,2,76,0) for magic date because the amount of 120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # overloaded numbers is minimized. The order in which searches for 121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # values within the format string is very important; it eliminates 122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # possible ambiguity for what something represents. 123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0)) 124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh date_time = [None, None, None] 125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh date_time[0] = time.strftime("%c", time_tuple).lower() 126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh date_time[1] = time.strftime("%x", time_tuple).lower() 127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh date_time[2] = time.strftime("%X", time_tuple).lower() 128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh replacement_pairs = [('%', '%%'), (self.f_weekday[2], '%A'), 129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh (self.f_month[3], '%B'), (self.a_weekday[2], '%a'), 130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh (self.a_month[3], '%b'), (self.am_pm[1], '%p'), 131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ('1999', '%Y'), ('99', '%y'), ('22', '%H'), 132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ('44', '%M'), ('55', '%S'), ('76', '%j'), 133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ('17', '%d'), ('03', '%m'), ('3', '%m'), 134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # '3' needed for when no leading zero. 135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ('2', '%w'), ('10', '%I')] 136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh replacement_pairs.extend([(tz, "%Z") for tz_values in self.timezone 137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for tz in tz_values]) 138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for offset,directive in ((0,'%c'), (1,'%x'), (2,'%X')): 139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh current_format = date_time[offset] 140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for old, new in replacement_pairs: 141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Must deal with possible lack of locale info 142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # manifesting itself as the empty string (e.g., Swedish's 143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # lack of AM/PM info) or a platform returning a tuple of empty 144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # strings (e.g., MacOS 9 having timezone as ('','')). 145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if old: 146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh current_format = current_format.replace(old, new) 147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # If %W is used, then Sunday, 2005-01-03 will fall on week 0 since 148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # 2005-01-03 occurs before the first Monday of the year. Otherwise 149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # %U is used. 150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0)) 151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if '00' in time.strftime(directive, time_tuple): 152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh U_W = '%W' 153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh U_W = '%U' 155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh date_time[offset] = current_format.replace('11', U_W) 156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.LC_date_time = date_time[0] 157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.LC_date = date_time[1] 158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.LC_time = date_time[2] 159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __calc_timezone(self): 161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Set self.timezone by using time.tzname. 162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Do not worry about possibility of time.tzname[0] == timetzname[1] 163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # and time.daylight; handle that in strptime . 164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh try: 165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time.tzset() 166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh except AttributeError: 167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh pass 168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh no_saving = frozenset(["utc", "gmt", time.tzname[0].lower()]) 169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if time.daylight: 170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh has_saving = frozenset([time.tzname[1].lower()]) 171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh has_saving = frozenset() 173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.timezone = (no_saving, has_saving) 174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TimeRE(dict): 177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Handle conversion from format directives to regexes.""" 178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self, locale_time=None): 180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Create keys/values. 181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Order of execution is important for dependency reasons. 183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if locale_time: 186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.locale_time = locale_time 187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.locale_time = LocaleTime() 189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh base = super(TimeRE, self) 190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh base.__init__({ 191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # The " \d" part of the regex is to make %c from ANSI C work 192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'd': r"(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", 193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'f': r"(?P<f>[0-9]{1,6})", 194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'H': r"(?P<H>2[0-3]|[0-1]\d|\d)", 195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'I': r"(?P<I>1[0-2]|0[1-9]|[1-9])", 196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh '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])", 197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'm': r"(?P<m>1[0-2]|0[1-9]|[1-9])", 198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'M': r"(?P<M>[0-5]\d|\d)", 199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'S': r"(?P<S>6[0-1]|[0-5]\d|\d)", 200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'U': r"(?P<U>5[0-3]|[0-4]\d|\d)", 201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'w': r"(?P<w>[0-6])", 202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # W is set below by using 'U' 203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'y': r"(?P<y>\d\d)", 204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh #XXX: Does 'Y' need to worry about having less or more than 205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # 4 digits? 206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'Y': r"(?P<Y>\d\d\d\d)", 207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'A': self.__seqToRE(self.locale_time.f_weekday, 'A'), 208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'a': self.__seqToRE(self.locale_time.a_weekday, 'a'), 209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'), 210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'b': self.__seqToRE(self.locale_time.a_month[1:], 'b'), 211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'p': self.__seqToRE(self.locale_time.am_pm, 'p'), 212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone 213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for tz in tz_names), 214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'Z'), 215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh '%': '%'}) 216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh base.__setitem__('W', base.__getitem__('U').replace('U', 'W')) 217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh base.__setitem__('c', self.pattern(self.locale_time.LC_date_time)) 218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh base.__setitem__('x', self.pattern(self.locale_time.LC_date)) 219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh base.__setitem__('X', self.pattern(self.locale_time.LC_time)) 220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __seqToRE(self, to_convert, directive): 222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Convert a list to a regex string for matching a directive. 223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Want possible matching values to be from longest to shortest. This 225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh prevents the possibility of a match occuring for a value that also 226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh a substring of a larger value that should have matched (e.g., 'abc' 227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh matching when 'abcdef' should have been the match). 228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh to_convert = sorted(to_convert, key=len, reverse=True) 231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for value in to_convert: 232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if value != '': 233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh break 234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return '' 236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh regex = '|'.join(re_escape(stuff) for stuff in to_convert) 237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh regex = '(?P<%s>%s' % (directive, regex) 238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return '%s)' % regex 239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def pattern(self, format): 241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Return regex pattern for the format string. 242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Need to make sure that any characters that might be interpreted as 244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh regex syntax are escaped. 245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh processed_format = '' 248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # The sub() call escapes all characters that might be misconstrued 249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # as regex syntax. Cannot use re.escape since we have to deal with 250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # format directives (%m, etc.). 251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh regex_chars = re_compile(r"([\\.^$*+?\(\){}\[\]|])") 252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh format = regex_chars.sub(r"\\\1", format) 253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh whitespace_replacement = re_compile('\s+') 254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh format = whitespace_replacement.sub('\s+', format) 255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh while '%' in format: 256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh directive_index = format.index('%')+1 257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh processed_format = "%s%s%s" % (processed_format, 258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh format[:directive_index-1], 259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self[format[directive_index]]) 260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh format = format[directive_index+1:] 261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return "%s%s" % (processed_format, format) 262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def compile(self, format): 264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Return a compiled re object for the format string.""" 265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return re_compile(self.pattern(format), IGNORECASE) 266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_cache_lock = _thread_allocate_lock() 268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# DO NOT modify _TimeRE_cache or _regex_cache without acquiring the cache lock 269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# first! 270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_TimeRE_cache = TimeRE() 271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_CACHE_MAX_SIZE = 5 # Max number of regexes stored in _regex_cache 272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_regex_cache = {} 273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef _calc_julian_from_U_or_W(year, week_of_year, day_of_week, week_starts_Mon): 275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Calculate the Julian day based on the year, week of the year, and day of 276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh the week, with week_start_day representing whether the week of the year 277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh assumes the week starts on Sunday or Monday (6 or 0).""" 278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh first_weekday = datetime_date(year, 1, 1).weekday() 279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # If we are dealing with the %U directive (week starts on Sunday), it's 280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # easier to just shift the view to Sunday being the first day of the 281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # week. 282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not week_starts_Mon: 283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh first_weekday = (first_weekday + 1) % 7 284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh day_of_week = (day_of_week + 1) % 7 285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Need to watch out for a week 0 (when the first day of the year is not 286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # the same as that specified by %U or %W). 287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_0_length = (7 - first_weekday) % 7 288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if week_of_year == 0: 289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 1 + day_of_week - first_weekday 290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh days_to_week = week_0_length + (7 * (week_of_year - 1)) 292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 1 + days_to_week + day_of_week 293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): 296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Return a time struct based on the input string and the format string.""" 297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh global _TimeRE_cache, _regex_cache 298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh with _cache_lock: 299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if _getlang() != _TimeRE_cache.locale_time.lang: 300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh _TimeRE_cache = TimeRE() 301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh _regex_cache.clear() 302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if len(_regex_cache) > _CACHE_MAX_SIZE: 303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh _regex_cache.clear() 304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh locale_time = _TimeRE_cache.locale_time 305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh format_regex = _regex_cache.get(format) 306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not format_regex: 307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh try: 308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh format_regex = _TimeRE_cache.compile(format) 309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # KeyError raised when a bad format is found; can be specified as 310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # \\, in which case it was a stray % but with a space after it 311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh except KeyError, err: 312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh bad_directive = err.args[0] 313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if bad_directive == "\\": 314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh bad_directive = "%" 315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh del err 316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise ValueError("'%s' is a bad directive in format '%s'" % 317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh (bad_directive, format)) 318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # IndexError only occurs when the format string is "%" 319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh except IndexError: 320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise ValueError("stray %% in format '%s'" % format) 321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh _regex_cache[format] = format_regex 322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh found = format_regex.match(data_string) 323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not found: 324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise ValueError("time data %r does not match format %r" % 325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh (data_string, format)) 326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if len(data_string) != found.end(): 327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise ValueError("unconverted data remains: %s" % 328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh data_string[found.end():]) 329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year = None 331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh month = day = 1 332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh hour = minute = second = fraction = 0 333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tz = -1 334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Default to -1 to signify that values not known; not critical to have, 335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # though 336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_of_year = -1 337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_of_year_start = -1 338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # weekday and julian defaulted to -1 so as to signal need to calculate 339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # values 340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday = julian = -1 341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh found_dict = found.groupdict() 342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for group_key in found_dict.iterkeys(): 343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Directives not explicitly handled below: 344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # c, x, X 345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # handled by making out of other directives 346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # U, W 347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # worthless without day of the week 348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if group_key == 'y': 349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year = int(found_dict['y']) 350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Open Group specification for strptime() states that a %y 351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh #value in the range of [00, 68] is in the century 2000, while 352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh #[69,99] is in the century 1900 353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if year <= 68: 354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year += 2000 355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year += 1900 357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'Y': 358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year = int(found_dict['Y']) 359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'm': 360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh month = int(found_dict['m']) 361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'B': 362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh month = locale_time.f_month.index(found_dict['B'].lower()) 363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'b': 364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh month = locale_time.a_month.index(found_dict['b'].lower()) 365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'd': 366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh day = int(found_dict['d']) 367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'H': 368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh hour = int(found_dict['H']) 369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'I': 370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh hour = int(found_dict['I']) 371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ampm = found_dict.get('p', '').lower() 372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # If there was no AM/PM indicator, we'll treat this like AM 373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if ampm in ('', locale_time.am_pm[0]): 374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # We're in AM so the hour is correct unless we're 375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # looking at 12 midnight. 376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # 12 midnight == 12 AM == hour 0 377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if hour == 12: 378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh hour = 0 379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif ampm == locale_time.am_pm[1]: 380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # We're in PM so we need to add 12 to the hour unless 381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # we're looking at 12 noon. 382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # 12 noon == 12 PM == hour 12 383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if hour != 12: 384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh hour += 12 385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'M': 386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh minute = int(found_dict['M']) 387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'S': 388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh second = int(found_dict['S']) 389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'f': 390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh s = found_dict['f'] 391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Pad to always return microseconds. 392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh s += "0" * (6 - len(s)) 393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh fraction = int(s) 394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'A': 395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday = locale_time.f_weekday.index(found_dict['A'].lower()) 396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'a': 397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday = locale_time.a_weekday.index(found_dict['a'].lower()) 398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'w': 399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday = int(found_dict['w']) 400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if weekday == 0: 401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday = 6 402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday -= 1 404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'j': 405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh julian = int(found_dict['j']) 406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key in ('U', 'W'): 407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_of_year = int(found_dict[group_key]) 408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if group_key == 'U': 409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # U starts week on Sunday. 410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_of_year_start = 6 411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # W starts week on Monday. 413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_of_year_start = 0 414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif group_key == 'Z': 415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Since -1 is default value only need to worry about setting tz if 416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # it can be something other than -1. 417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh found_zone = found_dict['Z'].lower() 418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for value, tz_values in enumerate(locale_time.timezone): 419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if found_zone in tz_values: 420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Deal with bad locale setup where timezone names are the 421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # same and yet time.daylight is true; too ambiguous to 422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # be able to tell what timezone has daylight savings 423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if (time.tzname[0] == time.tzname[1] and 424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time.daylight and found_zone not in ("utc", "gmt")): 425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh break 426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh tz = value 428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh break 429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh leap_year_fix = False 430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if year is None and month == 2 and day == 29: 431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year = 1904 # 1904 is first leap year of 20th century 432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh leap_year_fix = True 433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif year is None: 434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year = 1900 435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # If we know the week of the year and what day of that week, we can figure 436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # out the Julian day of the year. 437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if julian == -1 and week_of_year != -1 and weekday != -1: 438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_starts_Mon = True if week_of_year_start == 0 else False 439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh julian = _calc_julian_from_U_or_W(year, week_of_year, weekday, 440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh week_starts_Mon) 441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Cannot pre-calculate datetime_date() since can change in Julian 442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # calculation and thus could have different value for the day of the week 443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # calculation. 444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if julian == -1: 445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # Need to add 1 to result since first day of the year is 1, not 0. 446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh julian = datetime_date(year, month, day).toordinal() - \ 447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh datetime_date(year, 1, 1).toordinal() + 1 448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: # Assume that if they bothered to include Julian day it will 449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # be accurate. 450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh datetime_result = datetime_date.fromordinal((julian - 1) + datetime_date(year, 1, 1).toordinal()) 451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year = datetime_result.year 452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh month = datetime_result.month 453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh day = datetime_result.day 454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if weekday == -1: 455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday = datetime_date(year, month, day).weekday() 456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if leap_year_fix: 457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # the caller didn't supply a year but asked for Feb 29th. We couldn't 458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # use the default of 1900 for computations. We set it back to ensure 459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # that February 29th is smaller than March 1st. 460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh year = 1900 461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return (time.struct_time((year, month, day, 463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh hour, minute, second, 464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh weekday, julian, tz)), fraction) 465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef _strptime_time(data_string, format="%a %b %d %H:%M:%S %Y"): 467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return _strptime(data_string, format)[0] 468