2 date_interpreter.py - The module contains the MailIterator class.
4 Copyright (c) 2012 Intra2net AG
5 Author: Plamen Dimitrov
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
22 RECEIVED_DATE = re.compile(r'(0?[1-9]|[1-2][0-9]|3[01])\s+([A-Z][a-z][a-z])\s+'
23 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*'
24 r'(?:([-\+])([0-9]{2})([0-5][0-9]))*')
25 INTERNAL_DATE = re.compile(r'(?P<day>[ 0123][0-9])-(?P<mon>[A-Z][a-z][a-z])-(?P<year>[0-9][0-9][0-9][0-9])'
26 r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
27 r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])')
28 CONTROL_SYMBOLS = re.compile(r'[\n\r\t]')
30 class DateInterpreter:
31 """This class extracts dates from imap server responses and compares them.
32 This class contains only static methods."""
38 def extract_internal_date(cls, fetchresult):
39 """Extracts the internal date from INTERNALDATE, returns datetime."""
40 return datetime.datetime.fromtimestamp(time.mktime(fetchresult))
43 def extract_received_date(cls, fetchresult):
44 """Extracts the first date from RECEIVED, returns datetime."""
45 fetchresult = CONTROL_SYMBOLS.sub('', fetchresult[0][1].decode("utf-8"))
46 received_dates = RECEIVED_DATE.findall(fetchresult)
47 if(len(received_dates)==0):
49 else: received_date = received_dates[0]
50 #print("Retrieved date ", received_date, " from header ", fetchresult)
51 month = datetime.datetime.strptime(received_date[1],'%b').month
53 if(received_date[3]!=""):
54 hours = int(received_date[3])
56 if(received_date[4]!=""):
57 minutes = int(received_date[4])
59 if(received_date[5]!=""):
60 seconds = int(received_date[5])
63 if(received_date[6]!=""):
64 zonen = received_date[6]
66 if(received_date[7]!=""):
67 zoneh = int(received_date[7])
69 if(received_date[8]!=""):
70 zonem = int(received_date[8])
72 # subtract time zone to get unified time
73 zone = (zoneh * 60 + zonem) * 60
77 time_tuple = (int(received_date[2]), month, int(received_date[0]), hours, minutes, seconds, -1, -1, -1)
78 #'mktime' assumes arg in local timezone, so add timezone/altzone
79 utc = time.mktime(time_tuple)
81 if(time.daylight and time.localtime(utc)[-1]):
82 zone = zone + time.altzone
84 zone = zone + time.timezone
86 received_time_tuple = time.localtime(utc - zone)
87 converted_received_date = datetime.datetime.fromtimestamp(time.mktime(received_time_tuple))
88 return converted_received_date
91 def compare_dates(cls, date1, date2, tolerance=1800):
92 """Compares datetime objects for deviation given certain tolerance."""
93 """Returns 1 if there is a significant difference."""
94 #print(date1, "<>", date2)
95 timedelta = abs(date1 - date2)
96 if(timedelta.total_seconds()>tolerance):