def render(self, context): if self.boundfield is not None: if self.boundfield.field.disabled: self.label.attributes["_class"] += " bx--label--disabled" self.label.attributes["_for"] = self.boundfield.id_for_label self.label.append(self.boundfield.label) if not self.boundfield.field.required: self.label.append(_(" (optional)")) dateformat = ( self.boundfield.field.widget.format or formats.get_format(self.boundfield.field.widget.format_key)[0] ) dateformat_widget = to_php_formatstr( self.boundfield.field.widget.format, self.boundfield.field.widget.format_key, ) if self.simple: self.input.attributes["pattern"] = TimeRE().compile(dateformat).pattern else: self.input.attributes["data_date_format"] = dateformat_widget if self.boundfield.help_text: self[0][0].append(HelperText(self.boundfield.help_text)) if self.boundfield.errors: self.input.attributes["data-invalid"] = True self[1].append( Icon( "warning--filled", size=16, _class="bx--text-input__invalid-icon", ) ) self[0][0].append(ErrorList(self.boundfield.errors)) return super().render(context)
def strpdate(data_string, format='%Y-%m-%d', bc=False): _TimeRE_cache = TimeRE() _regex_cache = {} try: format_regex = _TimeRE_cache.compile(format) # KeyError raised when a bad format is found; can be specified as # \\, in which case it was a stray % but with a space after it except KeyError as err: bad_directive = err.args[0] if bad_directive == "\\": bad_directive = "%" del err raise ValueError("'%s' is a bad directive in format '%s'" % (bad_directive, format)) # IndexError only occurs when the format string is "%" except IndexError: raise ValueError("stray %% in format '%s'" % format) _regex_cache[format] = format_regex found = format_regex.match(data_string) if not found: raise ValueError("time data %r does not match format %r" % (data_string, format)) if len(data_string) != found.end(): raise ValueError("unconverted data remains: %s" % data_string[found.end():]) date = list(todaydatetuple()) found_dict = found.groupdict() for group_key in found_dict.keys(): if group_key == 'y': date[0] = int(found_dict['y']) if date[0] <= 68: date[0] += 2000 else: date[0] += 1900 elif group_key == 'Y': date[0] = int(found_dict['Y']) elif group_key == 'm': date[1] = int(found_dict['m']) elif group_key == 'd': date[2] = int(found_dict['d']) if not (bc and date == [1, 2, 29]): datetime(*date) return tuple(date)
def _tokenize_datetime(dt, fmt): try: time_re = _tokenize_datetime._time_re except AttributeError: from _strptime import TimeRE # Needed to work around timezone handling limitations time_re = _tokenize_datetime._time_re = TimeRE() time_re[ 'z'] = r'(?P<z>[+-]\d\d:?[0-5]\d)' # Allow ':' in timezone offset notation time_re[ 'Z'] = r'(?P<Z>[0-9A-Za-z_/+-]+)' # Allow any timezone possibly supported by pytz dt = str(dt) time_rx = time_re.compile(fmt) m = time_rx.match(dt) if not m: raise ValueError('time data {!r} does not match format {!r}'.format( dt, fmt)) if len(dt) != m.end(): raise ValueError('unconverted data remains: {}'.format(dt[m.end():])) return m.groupdict()
TZ_ABBR_RE = r"[A-Z](?:[A-Z]{2,4})?" FIXED_OFFSET_TZ_RE = re.compile(r"(%s)?([+-][01]\d(?::?\d{2})?)?$" % (TZ_ABBR_RE,)) def _getYearCentRE(cent=(0,3), distance=3, now=(MyTime.now(), MyTime.alternateNow)): """ Build century regex for last year and the next years (distance). Thereby respect possible run in the test-cases (alternate date used there) """ cent = lambda year, f=cent[0], t=cent[1]: str(year)[f:t] exprset = set( cent(now[0].year + i) for i in (-1, distance) ) if len(now) and now[1]: exprset |= set( cent(now[1].year + i) for i in (-1, distance) ) return "(?:%s)" % "|".join(exprset) if len(exprset) > 1 else "".join(exprset) timeRE = TimeRE() # %k - one- or two-digit number giving the hour of the day (0-23) on a 24-hour clock, # (corresponds %H, but allows space if not zero-padded). # %l - one- or two-digit number giving the hour of the day (12-11) on a 12-hour clock, # (corresponds %I, but allows space if not zero-padded). timeRE['k'] = r" ?(?P<H>[0-2]?\d)" timeRE['l'] = r" ?(?P<I>1?\d)" # TODO: because python currently does not support mixing of case-sensitive with case-insensitive matching, # check how TZ (in uppercase) can be combined with %a/%b etc. (that are currently case-insensitive), # to avoid invalid date-time recognition in strings like '11-Aug-2013 03:36:11.372 error ...' # with wrong TZ "error", which is at least not backwards compatible. # Hence %z currently match literal Z|UTC|GMT only (and offset-based), and %Exz - all zone abbreviations. timeRE['Z'] = r"(?P<Z>Z|[A-Z]{3,5})" timeRE['z'] = r"(?P<z>Z|UTC|GMT|[+-][01]\d(?::?\d{2})?)"
def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): """Return a 2-tuple consisting of a time struct and an int containing the number of microseconds based on the input string and the format string.""" for index, arg in enumerate([data_string, format]): if not isinstance(arg, str): msg = "strptime() argument {} must be str, not {}" raise TypeError(msg.format(index, type(arg))) global _TimeRE_cache, _regex_cache with _cache_lock: if _getlang() != _TimeRE_cache.locale_time.lang: _TimeRE_cache = TimeRE() _regex_cache.clear() if len(_regex_cache) > _CACHE_MAX_SIZE: _regex_cache.clear() locale_time = _TimeRE_cache.locale_time format_regex = _regex_cache.get(format) if not format_regex: try: format_regex = _TimeRE_cache.compile(format) # KeyError raised when a bad format is found; can be specified as # \\, in which case it was a stray % but with a space after it except KeyError as err: bad_directive = err.args[0] if bad_directive == "\\": bad_directive = "%" del err raise ValueError("'%s' is a bad directive in format '%s'" % (bad_directive, format)) # IndexError only occurs when the format string is "%" except IndexError: raise ValueError("stray %% in format '%s'" % format) _regex_cache[format] = format_regex found = format_regex.match(data_string) if not found: raise ValueError("time data %r does not match format %r" % (data_string, format)) if len(data_string) != found.end(): raise ValueError("unconverted data remains: %s" % data_string[found.end():]) year = 1900 month = day = 1 hour = minute = second = fraction = 0 tz = -1 tzoffset = None # Default to -1 to signify that values not known; not critical to have, # though week_of_year = -1 week_of_year_start = -1 # weekday and julian defaulted to -1 so as to signal need to calculate # values weekday = julian = -1 found_dict = found.groupdict() for group_key in found_dict.iterkeys(): # Directives not explicitly handled below: # c, x, X # handled by making out of other directives # U, W # worthless without day of the week if group_key == 'y': year = int(found_dict['y']) # Open Group specification for strptime() states that a %y #value in the range of [00, 68] is in the century 2000, while #[69,99] is in the century 1900 if year <= 68: year += 2000 else: year += 1900 elif group_key == 'Y': year = int(found_dict['Y']) elif group_key == 'm': month = int(found_dict['m']) elif group_key == 'B': month = locale_time.f_month.index(found_dict['B'].lower()) elif group_key == 'b': month = locale_time.a_month.index(found_dict['b'].lower()) elif group_key == 'd': day = int(found_dict['d']) elif group_key == 'H': hour = int(found_dict['H']) elif group_key == 'I': hour = int(found_dict['I']) ampm = found_dict.get('p', '').lower() # If there was no AM/PM indicator, we'll treat this like AM if ampm in ('', locale_time.am_pm[0]): # We're in AM so the hour is correct unless we're # looking at 12 midnight. # 12 midnight == 12 AM == hour 0 if hour == 12: hour = 0 elif ampm == locale_time.am_pm[1]: # We're in PM so we need to add 12 to the hour unless # we're looking at 12 noon. # 12 noon == 12 PM == hour 12 if hour != 12: hour += 12 elif group_key == 'M': minute = int(found_dict['M']) elif group_key == 'S': second = int(found_dict['S']) elif group_key == 'f': s = found_dict['f'] # Pad to always return microseconds. s += "0" * (6 - len(s)) fraction = int(s) elif group_key == 'A': weekday = locale_time.f_weekday.index(found_dict['A'].lower()) elif group_key == 'a': weekday = locale_time.a_weekday.index(found_dict['a'].lower()) elif group_key == 'w': weekday = int(found_dict['w']) if weekday == 0: weekday = 6 else: weekday -= 1 elif group_key == 'j': julian = int(found_dict['j']) elif group_key in ('U', 'W'): week_of_year = int(found_dict[group_key]) if group_key == 'U': # U starts week on Sunday. week_of_year_start = 6 else: # W starts week on Monday. week_of_year_start = 0 elif group_key == 'z': z = found_dict['z'] tzoffset = int(z[1:3]) * 60 + int(z[3:5]) if z.startswith("-"): tzoffset = -tzoffset elif group_key == 'Z': # Since -1 is default value only need to worry about setting tz if # it can be something other than -1. found_zone = found_dict['Z'].lower() for value, tz_values in enumerate(locale_time.timezone): if found_zone in tz_values: # Deal with bad locale setup where timezone names are the # same and yet time.daylight is true; too ambiguous to # be able to tell what timezone has daylight savings if (time.tzname[0] == time.tzname[1] and time.daylight and found_zone not in ("utc", "gmt")): break else: tz = value break # If we know the week of the year and what day of that week, we can figure # out the Julian day of the year. if julian == -1 and week_of_year != -1 and weekday != -1: week_starts_Mon = True if week_of_year_start == 0 else False julian = _calc_julian_from_U_or_W(year, week_of_year, weekday, week_starts_Mon) # Cannot pre-calculate datetime_date() since can change in Julian # calculation and thus could have different value for the day of the week # calculation. if julian == -1: # Need to add 1 to result since first day of the year is 1, not 0. julian = datetime_date(year, month, day).toordinal() - \ datetime_date(year, 1, 1).toordinal() + 1 else: # Assume that if they bothered to include Julian day it will # be accurate. datetime_result = datetime_date.fromordinal( (julian - 1) + datetime_date(year, 1, 1).toordinal()) year = datetime_result.year month = datetime_result.month day = datetime_result.day if weekday == -1: weekday = datetime_date(year, month, day).weekday() # Add timezone info tzname = found_dict.get("Z") if tzoffset is not None: gmtoff = tzoffset * 60 else: gmtoff = None return (year, month, day, hour, minute, second, weekday, julian, tz, gmtoff, tzname), fraction
while '%' in format: directive_index = format.index('%') + 1 processed_format = "%s%s%s" % (processed_format, format[:directive_index - 1], self[format[directive_index]]) format = format[directive_index + 1:] return "%s%s" % (processed_format, format) def compile(self, format): """Return a compiled re object for the format string.""" return re_compile(self.pattern(format), IGNORECASE) _cache_lock = _thread_allocate_lock() # DO NOT modify _TimeRE_cache or _regex_cache without acquiring the cache lock # first! _TimeRE_cache = TimeRE() _CACHE_MAX_SIZE = 5 # Max number of regexes stored in _regex_cache _regex_cache = {} def _calc_julian_from_U_or_W(year, week_of_year, day_of_week, week_starts_Mon): """Calculate the Julian day based on the year, week of the year, and day of the week, with week_start_day representing whether the week of the year assumes the week starts on Sunday or Monday (6 or 0).""" first_weekday = datetime_date(year, 1, 1).weekday() # If we are dealing with the %U directive (week starts on Sunday), it's # easier to just shift the view to Sunday being the first day of the # week. if not week_starts_Mon: first_weekday = (first_weekday + 1) % 7 day_of_week = (day_of_week + 1) % 7
def __init__( self, label=None, help_text=None, errors=None, inputelement_attrs=None, boundfield=None, style_short=False, style_simple=False, **attributes, ): inputelement_attrs = inputelement_attrs or {} def format_date_value(context): bfield = hg.resolve_lazy(boundfield, context) return bfield.field.widget.format_value(bfield.value()) super().__init__( hg.DIV( label, hg.If( style_simple, self.get_input_element( inputelement_attrs, errors, data_invalid=hg.If(getattr(errors, "condition"), True), pattern=hg.F(lambda c: (TimeRE().compile( hg.resolve_lazy(boundfield, c).field.widget.format or formats.get_format( hg.resolve_lazy(boundfield, c).field.widget. format_key)[0]).pattern)), value=hg.F(format_date_value), ), hg.DIV( self.get_input_element( inputelement_attrs, errors, data_date_picker_input=True, data_invalid=hg.If(getattr(errors, "condition"), True), data_date_format=hg.F(lambda c: to_php_formatstr( hg.resolve_lazy(boundfield, c).field.widget. format, hg.resolve_lazy(boundfield, c ).field.widget.format_key, )), value=hg.F(format_date_value), ), Icon( "calendar", size=16, _class="bx--date-picker__icon", data_date_picker_icon="true", ), _class="bx--date-picker-input__wrapper", ), ), help_text, errors, _class="bx--date-picker-container", ), **hg.merge_html_attrs( attributes, { "data_date_picker": not style_simple, "data_date_picker_type": None if style_simple else "single", "_class": hg.BaseElement( "bx--date-picker", hg.If( style_simple, " bx--date-picker--simple", " bx--date-picker--single", ), hg.If(style_short, " bx--date-picker--short"), ), }, ), )
def dateformatstr2regex(formatstr, format_key): formatstr = formatstr or formats.get_format(format_key)[0] # check: are local formats handled correctly? return TimeRE().compile(formatstr).pattern
def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): """Return a 2-tuple consisting of a time struct and an int containing the number of microseconds based on the input string and the format string.""" for index, arg in enumerate([data_string, format]): if not isinstance(arg, str): msg = "strptime() argument {} must be str, not {}" raise TypeError(msg.format(index, type(arg))) global _TimeRE_cache, _regex_cache with _cache_lock: if _getlang() != _TimeRE_cache.locale_time.lang: _TimeRE_cache = TimeRE() _regex_cache.clear() if len(_regex_cache) > _CACHE_MAX_SIZE: _regex_cache.clear() locale_time = _TimeRE_cache.locale_time format_regex = _regex_cache.get(format) if not format_regex: try: format_regex = _TimeRE_cache.compile(format) # KeyError raised when a bad format is found; can be specified as # \\, in which case it was a stray % but with a space after it except KeyError as err: bad_directive = err.args[0] if bad_directive == "\\": bad_directive = "%" del err raise ValueError("'%s' is a bad directive in format '%s'" % (bad_directive, format)) # IndexError only occurs when the format string is "%" except IndexError: raise ValueError("stray %% in format '%s'" % format) _regex_cache[format] = format_regex found = format_regex.match(data_string) if not found: raise ValueError("time data %r does not match format %r" % (data_string, format)) if len(data_string) != found.end(): raise ValueError("unconverted data remains: %s" % data_string[found.end():]) year = 1900 month = day = 1 hour = minute = second = fraction = 0 tz = -1 tzoffset = None # Default to -1 to signify that values not known; not critical to have, # though week_of_year = -1 week_of_year_start = -1 # weekday and julian defaulted to -1 so as to signal need to calculate # values weekday = julian = -1 found_dict = found.groupdict() for group_key in found_dict.iterkeys(): # Directives not explicitly handled below: # c, x, X # handled by making out of other directives # U, W # worthless without day of the week if group_key == 'y': year = int(found_dict['y']) # Open Group specification for strptime() states that a %y #value in the range of [00, 68] is in the century 2000, while #[69,99] is in the century 1900 if year <= 68: year += 2000 else: year += 1900 elif group_key == 'Y': year = int(found_dict['Y']) elif group_key == 'm': month = int(found_dict['m']) elif group_key == 'B': month = locale_time.f_month.index(found_dict['B'].lower()) elif group_key == 'b': month = locale_time.a_month.index(found_dict['b'].lower()) elif group_key == 'd': day = int(found_dict['d']) elif group_key == 'H': hour = int(found_dict['H']) elif group_key == 'I': hour = int(found_dict['I']) ampm = found_dict.get('p', '').lower() # If there was no AM/PM indicator, we'll treat this like AM if ampm in ('', locale_time.am_pm[0]): # We're in AM so the hour is correct unless we're # looking at 12 midnight. # 12 midnight == 12 AM == hour 0 if hour == 12: hour = 0 elif ampm == locale_time.am_pm[1]: # We're in PM so we need to add 12 to the hour unless # we're looking at 12 noon. # 12 noon == 12 PM == hour 12 if hour != 12: hour += 12 elif group_key == 'M': minute = int(found_dict['M']) elif group_key == 'S': second = int(found_dict['S']) elif group_key == 'f': s = found_dict['f'] # Pad to always return microseconds. s += "0" * (6 - len(s)) fraction = int(s) elif group_key == 'A': weekday = locale_time.f_weekday.index(found_dict['A'].lower()) elif group_key == 'a': weekday = locale_time.a_weekday.index(found_dict['a'].lower()) elif group_key == 'w': weekday = int(found_dict['w']) if weekday == 0: weekday = 6 else: weekday -= 1 elif group_key == 'j': julian = int(found_dict['j']) elif group_key in ('U', 'W'): week_of_year = int(found_dict[group_key]) if group_key == 'U': # U starts week on Sunday. week_of_year_start = 6 else: # W starts week on Monday. week_of_year_start = 0 elif group_key == 'z': z = found_dict['z'] tzoffset = int(z[1:3]) * 60 + int(z[3:5]) if z.startswith("-"): tzoffset = -tzoffset elif group_key == 'Z': # Since -1 is default value only need to worry about setting tz if # it can be something other than -1. found_zone = found_dict['Z'].lower() for value, tz_values in enumerate(locale_time.timezone): if found_zone in tz_values: # Deal with bad locale setup where timezone names are the # same and yet time.daylight is true; too ambiguous to # be able to tell what timezone has daylight savings if (time.tzname[0] == time.tzname[1] and time.daylight and found_zone not in ("utc", "gmt")): break else: tz = value break # If we know the week of the year and what day of that week, we can figure # out the Julian day of the year. if julian == -1 and week_of_year != -1 and weekday != -1: week_starts_Mon = True if week_of_year_start == 0 else False julian = _calc_julian_from_U_or_W(year, week_of_year, weekday, week_starts_Mon) # Cannot pre-calculate datetime_date() since can change in Julian # calculation and thus could have different value for the day of the week # calculation. if julian == -1: # Need to add 1 to result since first day of the year is 1, not 0. julian = datetime_date(year, month, day).toordinal() - \ datetime_date(year, 1, 1).toordinal() + 1 else: # Assume that if they bothered to include Julian day it will # be accurate. datetime_result = datetime_date.fromordinal((julian - 1) + datetime_date(year, 1, 1).toordinal()) year = datetime_result.year month = datetime_result.month day = datetime_result.day if weekday == -1: weekday = datetime_date(year, month, day).weekday() # Add timezone info tzname = found_dict.get("Z") if tzoffset is not None: gmtoff = tzoffset * 60 else: gmtoff = None return (year, month, day, hour, minute, second, weekday, julian, tz, gmtoff, tzname), fraction