_strptime.py revision 0eadaac7dc3ae49974c105ff9e8c1e98a04d7d5a
166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman"""Strptime-related classes and functions. 266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 366b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanCLASSES: 466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LocaleTime -- Discovers and/or stores locale-specific time information 566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman TimeRE -- Creates regexes for pattern matching a string of text containing 666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman time information as is returned by time.strftime() 766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 866b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanFUNCTIONS: 966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman _getlang -- Figure out what language is being used for the locale 1066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman strptime -- Calculates the time struct represented by the passed-in string 1166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 1266b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanRequires Python 2.2.1 or higher (mainly because of the use of property()). 1366b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanCan be used in Python 2.2 if the following line is added: 1466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman True = 1; False = 0 1566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman""" 1666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanimport time 1766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanimport locale 1866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanimport calendar 1966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanfrom re import compile as re_compile 2066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanfrom re import IGNORECASE 2166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanfrom datetime import date as datetime_date 2266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 2366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman__author__ = "Brett Cannon" 2466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman__email__ = "brett@python.org" 2566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 2666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman__all__ = ['strptime'] 2766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 2866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumandef _getlang(): 2966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Figure out what the current language is set to. 3066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman current_lang = locale.getlocale(locale.LC_TIME)[0] 3166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if current_lang: 3266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return current_lang 3366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 3466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman current_lang = locale.getdefaultlocale()[0] 3566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if current_lang: 3666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return current_lang 3766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 3866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return '' 3966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 4066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanclass LocaleTime(object): 4166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman """Stores and handles locale-specific information related to time. 4266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 4366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman ATTRIBUTES (all read-only after instance creation! Instance variables that 4466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman store the values have mangled names): 4566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman f_weekday -- full weekday names (7-item list) 4666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman a_weekday -- abbreviated weekday names (7-item list) 4766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman f_month -- full weekday names (14-item list; dummy value in [0], which 4866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman is added by code) 4966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman a_month -- abbreviated weekday names (13-item list, dummy value in 5066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman [0], which is added by code) 5166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman am_pm -- AM/PM representation (2-item list) 5266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LC_date_time -- format string for date/time representation (string) 5366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LC_date -- format string for date representation (string) 5466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LC_time -- format string for time representation (string) 5566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman timezone -- daylight- and non-daylight-savings timezone representation 5666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman (3-item list; code tacks on blank item at end for 5766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman possible lack of timezone such as UTC) 5866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman lang -- Language used by instance (string) 5966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman """ 6066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 6166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __init__(self, f_weekday=None, a_weekday=None, f_month=None, 6266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman a_month=None, am_pm=None, LC_date_time=None, LC_time=None, 6366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LC_date=None, timezone=None, lang=None): 6466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman """Optionally set attributes with passed-in values.""" 6566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if f_weekday is None: 6666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__f_weekday = None 6766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman elif len(f_weekday) == 7: 6866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__f_weekday = list(f_weekday) 6966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 7066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman raise TypeError("full weekday names must be a 7-item sequence") 7166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if a_weekday is None: 7266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__a_weekday = None 7366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman elif len(a_weekday) == 7: 7466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__a_weekday = list(a_weekday) 7566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 7666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman raise TypeError( 7766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman "abbreviated weekday names must be a 7-item sequence") 7866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if f_month is None: 7966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__f_month = None 8066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman elif len(f_month) == 12: 8166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__f_month = self.__pad(f_month, True) 8266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 8366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman raise TypeError("full month names must be a 12-item sequence") 8466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if a_month is None: 8566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__a_month = None 8666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman elif len(a_month) == 12: 8766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__a_month = self.__pad(a_month, True) 8866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 8966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman raise TypeError( 9066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman "abbreviated month names must be a 12-item sequence") 9166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if am_pm is None: 9266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__am_pm = None 9366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman elif len(am_pm) == 2: 9466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__am_pm = am_pm 9566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 9666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman raise TypeError("AM/PM representation must be a 2-item sequence") 9766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__LC_date_time = LC_date_time 9866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__LC_time = LC_time 9966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__LC_date = LC_date 10066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__timezone = timezone 10166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if timezone: 10266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if len(timezone) != 2: 10366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman raise TypeError("timezone names must contain 2 items") 10466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 10566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__timezone = self.__pad(timezone, False) 10666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__lang = lang 10766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 10866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __pad(self, seq, front): 10966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Add '' to seq to either front (is True), else the back. 11066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman seq = list(seq) 11166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if front: 11266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman seq.insert(0, '') 11366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman else: 11466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman seq.append('') 11566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return seq 11666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 11766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __set_nothing(self, stuff): 11866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Raise TypeError when trying to set an attribute. 11966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman raise TypeError("attribute does not support assignment") 12066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 12166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_f_weekday(self): 12266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.f_weekday. 12366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__f_weekday: 12466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_weekday() 12566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__f_weekday 12666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 12766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_a_weekday(self): 12866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.a_weekday. 12966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__a_weekday: 13066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_weekday() 13166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__a_weekday 13266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 13366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman f_weekday = property(__get_f_weekday, __set_nothing, 13466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Full weekday names") 13566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman a_weekday = property(__get_a_weekday, __set_nothing, 13666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Abbreviated weekday names") 13766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 13866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_f_month(self): 13966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.f_month. 14066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__f_month: 14166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_month() 14266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__f_month 14366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 14466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_a_month(self): 14566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.a_month. 14666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__a_month: 14766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_month() 14866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__a_month 14966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 15066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman f_month = property(__get_f_month, __set_nothing, 15166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Full month names (dummy value at index 0)") 15266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman a_month = property(__get_a_month, __set_nothing, 15366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Abbreviated month names (dummy value at index 0)") 15466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 15566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_am_pm(self): 15666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.am_pm. 15766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__am_pm: 15866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_am_pm() 15966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__am_pm 16066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 16166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman am_pm = property(__get_am_pm, __set_nothing, doc="AM/PM representation") 16266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 16366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_timezone(self): 16466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.timezone. 16566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__timezone: 16666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_timezone() 16766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__timezone 16866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 16966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman timezone = property(__get_timezone, __set_nothing, 17066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Timezone representation (dummy value at index 2)") 17166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 17266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_LC_date_time(self): 17366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.LC_date_time. 17466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__LC_date_time: 17566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_date_time() 17666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__LC_date_time 17766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 17866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_LC_date(self): 17966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.LC_date. 18066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__LC_date: 18166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_date_time() 18266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__LC_date 18366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 18466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_LC_time(self): 18566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.LC_time. 18666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__LC_time: 18766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_date_time() 18866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__LC_time 18966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 19066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LC_date_time = property( 19166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman __get_LC_date_time, __set_nothing, 19266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc= 19366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman "Format string for locale's date/time representation ('%c' format)") 19466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LC_date = property(__get_LC_date, __set_nothing, 19566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Format string for locale's date representation ('%x' format)") 19666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman LC_time = property(__get_LC_time, __set_nothing, 19766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Format string for locale's time representation ('%X' format)") 19866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 19966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __get_lang(self): 20066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Fetch self.lang. 20166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__lang: 20266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__calc_lang() 20366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman return self.__lang 20466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 20566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman lang = property(__get_lang, __set_nothing, 20666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman doc="Language used for instance") 20766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 20866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __calc_weekday(self): 20966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Set self.__a_weekday and self.__f_weekday using the calendar 21066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # module. 21166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman a_weekday = [calendar.day_abbr[i] for i in range(7)] 21266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman f_weekday = [calendar.day_name[i] for i in range(7)] 21366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__a_weekday: 21466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__a_weekday = a_weekday 21566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__f_weekday: 21666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__f_weekday = f_weekday 21766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 21866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __calc_month(self): 21966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Set self.__f_month and self.__a_month using the calendar module. 22066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman a_month = [calendar.month_abbr[i] for i in range(13)] 22166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman f_month = [calendar.month_name[i] for i in range(13)] 22266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__a_month: 22366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__a_month = a_month 22466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman if not self.__f_month: 22566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__f_month = f_month 22666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 22766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __calc_am_pm(self): 22866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Set self.__am_pm by using time.strftime(). 22966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 23066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # The magic date (1999,3,17,hour,44,55,2,76,0) is not really that 23166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # magical; just happened to have used it everywhere else where a 23266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # static date was needed. 23366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman am_pm = [] 23466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman for hour in (01,22): 23566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman time_tuple = time.struct_time((1999,3,17,hour,44,55,2,76,0)) 23666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman am_pm.append(time.strftime("%p", time_tuple)) 23766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman self.__am_pm = am_pm 23866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 23966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman def __calc_date_time(self): 24066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Set self.__date_time, self.__date, & self.__time by using 24166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # time.strftime(). 24266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman 24366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # Use (1999,3,17,22,44,55,2,76,0) for magic date because the amount of 24466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # overloaded numbers is minimized. The order in which searches for 24566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # values within the format string is very important; it eliminates 24666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman # possible ambiguity for what something represents. 24766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0)) 248 date_time = [None, None, None] 249 date_time[0] = time.strftime("%c", time_tuple) 250 date_time[1] = time.strftime("%x", time_tuple) 251 date_time[2] = time.strftime("%X", time_tuple) 252 for offset,directive in ((0,'%c'), (1,'%x'), (2,'%X')): 253 current_format = date_time[offset] 254 for old, new in ( 255 ('%', '%%'), (self.f_weekday[2], '%A'), 256 (self.f_month[3], '%B'), (self.a_weekday[2], '%a'), 257 (self.a_month[3], '%b'), (self.am_pm[1], '%p'), 258 (self.timezone[0], '%Z'), (self.timezone[1], '%Z'), 259 ('1999', '%Y'), ('99', '%y'), ('22', '%H'), 260 ('44', '%M'), ('55', '%S'), ('76', '%j'), 261 ('17', '%d'), ('03', '%m'), ('3', '%m'), 262 # '3' needed for when no leading zero. 263 ('2', '%w'), ('10', '%I')): 264 # Must deal with possible lack of locale info 265 # manifesting itself as the empty string (e.g., Swedish's 266 # lack of AM/PM info) or a platform returning a tuple of empty 267 # strings (e.g., MacOS 9 having timezone as ('','')). 268 if old: 269 current_format = current_format.replace(old, new) 270 time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0)) 271 if time.strftime(directive, time_tuple).find('00'): 272 U_W = '%U' 273 else: 274 U_W = '%W' 275 date_time[offset] = current_format.replace('11', U_W) 276 if not self.__LC_date_time: 277 self.__LC_date_time = date_time[0] 278 if not self.__LC_date: 279 self.__LC_date = date_time[1] 280 if not self.__LC_time: 281 self.__LC_time = date_time[2] 282 283 def __calc_timezone(self): 284 # Set self.__timezone by using time.tzname. 285 # 286 # Empty string used for matching when timezone is not used/needed such 287 # as with UTC. 288 self.__timezone = self.__pad(time.tzname, 0) 289 290 def __calc_lang(self): 291 # Set self.__lang by using __getlang(). 292 self.__lang = _getlang() 293 294 295 296class TimeRE(dict): 297 """Handle conversion from format directives to regexes.""" 298 299 def __init__(self, locale_time=LocaleTime()): 300 """Init inst with non-locale regexes and store LocaleTime object.""" 301 #XXX: Does 'Y' need to worry about having less or more than 4 digits? 302 base = super(TimeRE, self) 303 base.__init__({ 304 # The " \d" option is to make %c from ANSI C work 305 'd': r"(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])", 306 'H': r"(?P<H>2[0-3]|[0-1]\d|\d)", 307 'I': r"(?P<I>1[0-2]|0[1-9]|[1-9])", 308 '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])", 309 'm': r"(?P<m>1[0-2]|0[1-9]|[1-9])", 310 'M': r"(?P<M>[0-5]\d|\d)", 311 'S': r"(?P<S>6[0-1]|[0-5]\d|\d)", 312 'U': r"(?P<U>5[0-3]|[0-4]\d|\d)", 313 'w': r"(?P<w>[0-6])", 314 # W is set below by using 'U' 315 'y': r"(?P<y>\d\d)", 316 'Y': r"(?P<Y>\d\d\d\d)"}) 317 base.__setitem__('W', base.__getitem__('U')) 318 self.locale_time = locale_time 319 320 def __getitem__(self, fetch): 321 """Try to fetch regex; if it does not exist, construct it.""" 322 try: 323 return super(TimeRE, self).__getitem__(fetch) 324 except KeyError: 325 constructors = { 326 'A': lambda: self.__seqToRE(self.locale_time.f_weekday, fetch), 327 'a': lambda: self.__seqToRE(self.locale_time.a_weekday, fetch), 328 'B': lambda: self.__seqToRE(self.locale_time.f_month[1:], 329 fetch), 330 'b': lambda: self.__seqToRE(self.locale_time.a_month[1:], 331 fetch), 332 'c': lambda: self.pattern(self.locale_time.LC_date_time), 333 'p': lambda: self.__seqToRE(self.locale_time.am_pm, fetch), 334 'x': lambda: self.pattern(self.locale_time.LC_date), 335 'X': lambda: self.pattern(self.locale_time.LC_time), 336 'Z': lambda: self.__seqToRE(self.locale_time.timezone, fetch), 337 '%': lambda: '%', 338 } 339 if fetch in constructors: 340 self[fetch] = constructors[fetch]() 341 return self[fetch] 342 else: 343 raise 344 345 def __seqToRE(self, to_convert, directive): 346 """Convert a list to a regex string for matching a directive.""" 347 def sorter(a, b): 348 """Sort based on length. 349 350 Done in case for some strange reason that names in the locale only 351 differ by a suffix and thus want the name with the suffix to match 352 first. 353 """ 354 try: 355 a_length = len(a) 356 except TypeError: 357 a_length = 0 358 try: 359 b_length = len(b) 360 except TypeError: 361 b_length = 0 362 return cmp(b_length, a_length) 363 364 to_convert = to_convert[:] # Don't want to change value in-place. 365 for value in to_convert: 366 if value != '': 367 break 368 else: 369 return '' 370 to_convert.sort(sorter) 371 regex = '|'.join(to_convert) 372 regex = '(?P<%s>%s' % (directive, regex) 373 return '%s)' % regex 374 375 def pattern(self, format): 376 """Return re pattern for the format string. 377 378 Need to make sure that any characters that might be interpreted as 379 regex syntax is escaped. 380 381 """ 382 processed_format = '' 383 # The sub() call escapes all characters that might be misconstrued 384 # as regex syntax. 385 regex_chars = re_compile(r"([\\.^$*+?{}\[\]|])") 386 format = regex_chars.sub(r"\\\1", format) 387 whitespace_replacement = re_compile('\s+') 388 format = whitespace_replacement.sub('\s*', format) 389 while format.find('%') != -1: 390 directive_index = format.index('%')+1 391 processed_format = "%s%s%s" % (processed_format, 392 format[:directive_index-1], 393 self[format[directive_index]]) 394 format = format[directive_index+1:] 395 return "%s%s" % (processed_format, format) 396 397 def compile(self, format): 398 """Return a compiled re object for the format string.""" 399 return re_compile(self.pattern(format), IGNORECASE) 400 401# Cached TimeRE; probably only need one instance ever so cache it for performance 402_locale_cache = TimeRE() 403# Cached regex objects; same reason as for TimeRE cache 404_regex_cache = dict() 405 406def strptime(data_string, format="%a %b %d %H:%M:%S %Y"): 407 """Return a time struct based on the input data and the format string.""" 408 global _locale_cache 409 global _regex_cache 410 locale_time = _locale_cache.locale_time 411 # If the language changes, caches are invalidated, so clear them 412 if locale_time.lang != _getlang(): 413 _locale_cache = TimeRE() 414 _regex_cache.clear() 415 format_regex = _regex_cache.get(format) 416 if not format_regex: 417 # Limit regex cache size to prevent major bloating of the module; 418 # The value 5 is arbitrary 419 if len(_regex_cache) > 5: 420 _regex_cache.clear() 421 format_regex = _locale_cache.compile(format) 422 _regex_cache[format] = format_regex 423 found = format_regex.match(data_string) 424 if not found: 425 raise ValueError("time data did not match format") 426 year = 1900 427 month = day = 1 428 hour = minute = second = 0 429 tz = -1 430 # weekday and julian defaulted to -1 so as to signal need to calculate values 431 weekday = julian = -1 432 found_dict = found.groupdict() 433 for group_key in found_dict.iterkeys(): 434 if group_key == 'y': 435 year = int(found_dict['y']) 436 # Open Group specification for strptime() states that a %y 437 #value in the range of [00, 68] is in the century 2000, while 438 #[69,99] is in the century 1900 439 if year <= 68: 440 year += 2000 441 else: 442 year += 1900 443 elif group_key == 'Y': 444 year = int(found_dict['Y']) 445 elif group_key == 'm': 446 month = int(found_dict['m']) 447 elif group_key == 'B': 448 month = _insensitiveindex(locale_time.f_month, found_dict['B']) 449 elif group_key == 'b': 450 month = _insensitiveindex(locale_time.a_month, found_dict['b']) 451 elif group_key == 'd': 452 day = int(found_dict['d']) 453 elif group_key is 'H': 454 hour = int(found_dict['H']) 455 elif group_key == 'I': 456 hour = int(found_dict['I']) 457 ampm = found_dict.get('p', '').lower() 458 # If there was no AM/PM indicator, we'll treat this like AM 459 if ampm in ('', locale_time.am_pm[0].lower()): 460 # We're in AM so the hour is correct unless we're 461 # looking at 12 midnight. 462 # 12 midnight == 12 AM == hour 0 463 if hour == 12: 464 hour = 0 465 elif ampm == locale_time.am_pm[1].lower(): 466 # We're in PM so we need to add 12 to the hour unless 467 # we're looking at 12 noon. 468 # 12 noon == 12 PM == hour 12 469 if hour != 12: 470 hour += 12 471 elif group_key == 'M': 472 minute = int(found_dict['M']) 473 elif group_key == 'S': 474 second = int(found_dict['S']) 475 elif group_key == 'A': 476 weekday = _insensitiveindex(locale_time.f_weekday, 477 found_dict['A']) 478 elif group_key == 'a': 479 weekday = _insensitiveindex(locale_time.a_weekday, 480 found_dict['a']) 481 elif group_key == 'w': 482 weekday = int(found_dict['w']) 483 if weekday == 0: 484 weekday = 6 485 else: 486 weekday -= 1 487 elif group_key == 'j': 488 julian = int(found_dict['j']) 489 elif group_key == 'Z': 490 found_zone = found_dict['Z'].lower() 491 if locale_time.timezone[0] == locale_time.timezone[1]: 492 pass #Deals with bad locale setup where timezone info is 493 # the same; first found on FreeBSD 4.4. 494 elif locale_time.timezone[0].lower() == found_zone: 495 tz = 0 496 elif locale_time.timezone[1].lower() == found_zone: 497 tz = 1 498 elif locale_time.timezone[2].lower() == found_zone: 499 tz = -1 500 # Cannot pre-calculate datetime_date() since can change in Julian 501 #calculation and thus could have different value for the day of the week 502 #calculation 503 if julian == -1: 504 # Need to add 1 to result since first day of the year is 1, not 0. 505 julian = datetime_date(year, month, day).toordinal() - \ 506 datetime_date(year, 1, 1).toordinal() + 1 507 else: # Assume that if they bothered to include Julian day it will 508 #be accurate 509 datetime_result = datetime_date.fromordinal((julian - 1) + datetime_date(year, 1, 1).toordinal()) 510 year = datetime_result.year 511 month = datetime_result.month 512 day = datetime_result.day 513 if weekday == -1: 514 weekday = datetime_date(year, month, day).weekday() 515 return time.struct_time((year, month, day, 516 hour, minute, second, 517 weekday, julian, tz)) 518 519def _insensitiveindex(lst, findme): 520 # Perform a case-insensitive index search. 521 522 #XXX <bc>: If LocaleTime is not exposed, then consider removing this and 523 # just lowercase when LocaleTime sets its vars and lowercasing 524 # search values. 525 findme = findme.lower() 526 for key,item in enumerate(lst): 527 if item.lower() == findme: 528 return key 529 else: 530 raise ValueError("value not in list") 531