''' date_interpreter.py - The module contains the MailIterator class. Copyright (c) 2012 Intra2net AG Author: Plamen Dimitrov This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ''' import datetime, time import re import logging #reg expressions RECEIVED_DATE = re.compile(r'(0?[1-9]|[1-2][0-9]|3[01])\s+([A-Z][a-z][a-z])\s+' r'(19[0-9]{2}|[2-9][0-9]{3}|[0-9]{2})\s+(2[0-3]|[0-1][0-9]):([0-5][0-9])(?::(60|[0-5][0-9]))?\s*' r'(?:([-\+])([0-9]{2})([0-5][0-9]))*') INTERNAL_DATE = re.compile(r'(?P[ 0123][0-9])-(?P[A-Z][a-z][a-z])-(?P[0-9][0-9][0-9][0-9])' r' (?P[0-9][0-9]):(?P[0-9][0-9]):(?P[0-9][0-9])' r' (?P[-+])(?P[0-9][0-9])(?P[0-9][0-9])') CONTROL_SYMBOLS = re.compile(r'[\n\r\t]') class DateInterpreter: """This class extracts dates from imap server responses and compares them. This class contains only static methods.""" def __init__(self): return @classmethod def extract_internal_date(cls, fetchresult): """Extracts the internal date from INTERNALDATE, returns datetime.""" return datetime.datetime.fromtimestamp(time.mktime(fetchresult)) @classmethod def extract_received_date(cls, fetchresult): """Extracts the first date from RECEIVED, returns datetime.""" fetchresult = CONTROL_SYMBOLS.sub('', fetchresult[0][1].decode("utf-8")) received_dates = RECEIVED_DATE.findall(fetchresult) if(len(received_dates)==0): return "" else: received_date = received_dates[0] logging.debug("Retrieved date %s from header %s.", received_date, fetchresult) month = datetime.datetime.strptime(received_date[1],'%b').month if(received_date[3]!=""): hours = int(received_date[3]) else: hours = 0 if(received_date[4]!=""): minutes = int(received_date[4]) else: minutes = 0 if(received_date[5]!=""): seconds = int(received_date[5]) else: seconds = 0 if(received_date[6]!=""): zonen = received_date[6] else: zonen = b'+' if(received_date[7]!=""): zoneh = int(received_date[7]) else: zoneh = 0 if(received_date[8]!=""): zonem = int(received_date[8]) else: zonem = 0 # subtract time zone to get unified time zone = (zoneh * 60 + zonem) * 60 if(zonen == b'-'): zone = -zone time_tuple = (int(received_date[2]), month, int(received_date[0]), hours, minutes, seconds, -1, -1, -1) #'mktime' assumes arg in local timezone, so add timezone/altzone utc = time.mktime(time_tuple) #adjust to DST if(time.daylight and time.localtime(utc)[-1]): zone = zone + time.altzone else: zone = zone + time.timezone received_time_tuple = time.localtime(utc - zone) converted_received_date = datetime.datetime.fromtimestamp(time.mktime(received_time_tuple)) return converted_received_date @classmethod def compare_dates(cls, date1, date2, tolerance=1800): """Compares datetime objects for deviation given certain tolerance.""" """Returns 1 if there is a significant difference.""" logging.debug("Comparing dates %s <> %s.", date1, date2) timedelta = abs(date1 - date2) if(timedelta.total_seconds()>tolerance): return True else: return False