from fb_tools.obj import FbGenericBaseObject
# Own modules
+from .errors import DateFormatError
+from .errors import WrongDateIsoformatError
+from .tzlocal import get_localzone
from .xlate import XLATOR
_ = XLATOR.gettext
ngettext = XLATOR.ngettext
-__version__ = '0.6.0'
+__version__ = '0.6.1'
LOG = logging.getLogger(__name__)
UTC = utc = datetime.timezone(datetime.timedelta(), 'UTC')
+PATTERN_ISODATE = r'(?P<year>\d{4})-?(?P<month>[01]\d)-?(?P<day>[0-3]\d)'
+PATTERN_ISOTIME = (
+ r'(?P<hour>[0-2]\d):?(?P<min>[0-5]\d)(?::?(?P<sec>[0-5]\d)(\.(?P<nsec>\d+))?)?')
+PATTERN_ISOTIMEZONE = r'((?P<utc>Z)|(?P<tz_hours>[+-][01]\d)(?::?(?P<tz_mins>[0-5]\d))?)?'
+
+RE_ISODATETIME = re.compile(PATTERN_ISODATE + r'[T\s]' + PATTERN_ISOTIME + PATTERN_ISOTIMEZONE)
+
+
+# =============================================================================
+def fromisoformat(datestr):
+ """Try to convert a string with an ISO-formatted timestamp into a datetime object."""
+ if hasattr(datetime.datetime, 'fromisoformat'):
+ try:
+ ret = datetime.datetime.fromisoformat(datestr)
+ return ret
+ except ValueError as e:
+ raise DateFormatError(str(e))
+
+ match_obj = RE_ISODATETIME.search(datestr)
+ if not match_obj:
+ raise WrongDateIsoformatError(datestr)
+
+ params = {
+ 'year': int(match_obj['year']),
+ 'month': int(match_obj['month']),
+ 'day': int(match_obj['day']),
+ 'minute': int(match_obj['min']),
+ }
+ if match_obj['sec'] is not None:
+ params['second'] = int(match_obj['sec'])
+
+ if match_obj['nsec'] is not None:
+ params['microsecond'] = int(round(float('0.' + match_obj['nsec']) * 1000000))
+
+ if match_obj['utc']:
+ params['tzinfo'] = UTC
+ elif match_obj['tz_hours'] is not None:
+ prefix = match_obj['tz_hours'][0]
+ offset = 0
+ if match_obj['tz_mins'] is not None:
+ offset = int(match_obj['tz_mins']) * 60
+ offset += int(match_obj['tz_hours'][1:]) * 3600
+ if prefix == '-':
+ offset *= -1
+
+ params['tzinfo'] = datetime.timezone(datetime.timedelta(seconds=offset))
+ else:
+ params['tzinfo'] = get_localzone()
+
+ return datetime.datetime(**params)
+
# =============================================================================
class DataPair(object):
class PostfixLogchainInfo(FbGenericBaseObject):
"""A class for encapsulating the information from a chain of Postfix log entries."""
- pattern_isodate = r'(?P<year>\d{4})-?(?P<month>[01]\d)-?(?P<day>[0-3]\d)'
- pattern_isotime = (
- r'(?P<hour>[0-2]\d):?(?P<min>[0-5]\d)(?::?(?P<sec>[0-5]\d)(\.(?P<nsec>\d+))?)?')
- pattern_isotimezone = r'((?P<utc>Z)|(?P<tz_hours>[+-][01]\d)(?::?(?P<tz_mins>[0-5]\d))?)?'
-
- re_isodatetime = re.compile(
- pattern_isodate + r'[T\s]' + pattern_isotime + pattern_isotimezone)
-
warn_on_parse_error = True
attributes = (
"""Append the given mail address to the list of TO addresses."""
self.to_addresses.append(address)
- # -------------------------------------------------------------------------
- @classmethod
- def date_fromisoformat(cls, datestr):
- """Try to convert a string with an ISO-fromatted timestamp into a datetime object."""
- m = cls.re_isodatetime.search(datestr)
- if not m:
- return None
-
- params = {
- 'year': int(m['year']),
- 'month': int(m['month']),
- 'day': int(m['day']),
- 'minute': int(m['min']),
- }
- if m['sec'] is not None:
- params['second'] = int(m['sec'])
-
- if m['nsec'] is not None:
- params['microsecond'] = int(round(float('0.' + m['nsec']) * 1000000))
-
- if m['utc']:
- params['tzinfo'] = UTC
- elif m['tz_hours'] is not None:
- prefix = m['tz_hours'][0]
- offset = 0
- if m['tz_mins'] is not None:
- offset = int(m['tz_mins']) * 60
- offset += int(m['tz_hours'][1:]) * 3600
- if prefix == '-':
- offset *= -1
-
- params['tzinfo'] = datetime.timezone(datetime.timedelta(seconds=offset))
-
- return datetime.datetime(**params)
-
# -----------------------------------------------------------
@property
def auth(self):
self._end = None
return
- if hasattr(datetime.datetime, 'fromisoformat'):
- ts_end = datetime.datetime.fromisoformat(val)
- else:
- ts_end = self.date_fromisoformat(val)
+ try:
+ ts_end = fromisoformat(val)
+ except DateFormatError as e:
+ msg = _('Could not interprete date {!r}:').format(val) + ' ' + str(e)
+ if self.warn_on_parse_error:
+ LOG.warn(msg)
+ else:
+ LOG.debug(msg)
+ ts_end = None
if ts_end:
self._end = ts_end
return
self._start = None
return
- if hasattr(datetime.datetime, 'fromisoformat'):
- ts_start = datetime.datetime.fromisoformat(val)
- else:
- ts_start = self.date_fromisoformat(val)
+ try:
+ ts_start = fromisoformat(val)
+ except DateFormatError as e:
+ msg = _('Could not interprete date {!r}:').format(val) + ' ' + str(e)
+ if self.warn_on_parse_error:
+ LOG.warn(msg)
+ else:
+ LOG.debug(msg)
+ ts_start = None
if ts_start:
self._start = ts_start
return