Commit | Line | Data |
---|---|---|
c9da760a PD |
1 | ''' |
2 | date_interpreter.py - The module contains the MailIterator class. | |
3 | ||
4 | Copyright (c) 2012 Intra2net AG | |
5 | Author: Plamen Dimitrov | |
6 | ||
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. | |
11 | ||
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. | |
c9da760a PD |
16 | ''' |
17 | ||
7a1d4c35 | 18 | import datetime, time |
c9da760a | 19 | import re |
c9da760a PD |
20 | |
21 | #reg expressions | |
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]') | |
29 | ||
30 | class DateInterpreter: | |
7a1d4c35 PD |
31 | """This class extracts dates from imap server responses and compares them. |
32 | This class contains only static methods.""" | |
c9da760a PD |
33 | |
34 | def __init__(self): | |
35 | return | |
36 | ||
37 | @classmethod | |
38 | def extract_internal_date(cls, fetchresult): | |
39 | """Extracts the internal date from INTERNALDATE, returns datetime.""" | |
40 | return datetime.datetime.fromtimestamp(time.mktime(fetchresult)) | |
41 | ||
42 | @classmethod | |
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): | |
48 | return "" | |
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 | |
52 | ||
53 | if(received_date[3]!=""): | |
54 | hours = int(received_date[3]) | |
55 | else: hours = 0 | |
56 | if(received_date[4]!=""): | |
57 | minutes = int(received_date[4]) | |
58 | else: minutes = 0 | |
59 | if(received_date[5]!=""): | |
60 | seconds = int(received_date[5]) | |
61 | else: seconds = 0 | |
62 | ||
63 | if(received_date[6]!=""): | |
64 | zonen = received_date[6] | |
65 | else: zonen = b'+' | |
66 | if(received_date[7]!=""): | |
67 | zoneh = int(received_date[7]) | |
68 | else: zoneh = 0 | |
69 | if(received_date[8]!=""): | |
70 | zonem = int(received_date[8]) | |
71 | else: zonem = 0 | |
72 | # subtract time zone to get unified time | |
73 | zone = (zoneh * 60 + zonem) * 60 | |
74 | if(zonen == b'-'): | |
75 | zone = -zone | |
76 | ||
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) | |
80 | #adjust to DST | |
81 | if(time.daylight and time.localtime(utc)[-1]): | |
82 | zone = zone + time.altzone | |
83 | else: | |
84 | zone = zone + time.timezone | |
85 | ||
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 | |
89 | ||
90 | @classmethod | |
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): | |
8301e589 | 97 | return True |
c9da760a | 98 | else: |
8301e589 | 99 | return False |