1
0
mirror of https://github.com/OfflineIMAP/offlineimap.git synced 2024-06-25 07:27:44 +02:00

Fix IMAP folder throwing away time zone when parsing email Date headers

Fix imapfolder.getmessageinternaldate misparsing the Date:
header from emails due to a bug or surprising behaviour by
email.utils.parsedate. This is because email.utils.parsedate's
return value contains the unadjusted hour value from the string
parsed but does not include information about the time zone in
which it is specified. For example (Python 2.7.3):

$ python -c "import email.utils;
  print email.utils.parsedate('Mon, 20 Nov 1995 19:12:08 -0500')"
 (1995, 11, 20, 19, 12, 8, 0, 1, -1)

(the -1 is the isdst field); the -0500 time zone is completely
ignored, so e.g. the same input with time "19:12:08 +0300" has
the same result. When passed to time.struct_time as allowed per
the parsedate documentation, this time is interpreted in GMT and
thus deviates from the correct value by the timezone offset
(in this example, -5 hours).

I consider this a bug in email.utils.parsedate: In my opinion,
since the return value of the parsetime doesn't include a timezone,
it should be expressed in terms of UTC rather than in terms of the
time zone from the Date header; the existence of
email.utils.parsedate_tz, to which I've switched, indicates that
maybe the authors were aware of this problem.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
This commit is contained in:
Tobias Thierer 2012-10-01 20:30:00 +10:00 committed by Sebastian Spaeth
parent 5eef3ae473
commit caef9a72fc
2 changed files with 8 additions and 6 deletions

View File

@ -7,6 +7,8 @@ ChangeLog
WIP (add new stuff for the next release)
========================================
* Honor the timezone of emails (Tobias Thierer)
OfflineIMAP v6.5.5-rc1 (2012-09-05)
===================================

View File

@ -432,16 +432,16 @@ class IMAPFolder(BaseFolder):
(which is fine as value for append)."""
if rtime is None:
message = email.message_from_string(content)
# parsedate returns a 9-tuple that can be passed directly to
# time.mktime(); Will be None if missing or not in a valid
# format. Note that indexes 6, 7, and 8 of the result tuple are
# not usable.
datetuple = email.utils.parsedate(message.get('Date'))
dateheader = message.get('Date')
# parsedate_tz returns a 10-tuple that can be passed to mktime_tz;
# Will be None if missing or not in a valid format. Note that
# indexes 6, 7, and 8 of the result tuple are not usable.
datetuple = email.utils.parsedate_tz(dateheader)
if datetuple is None:
#could not determine the date, use the local time.
return None
#make it a real struct_time, so we have named attributes
datetuple = time.struct_time(datetuple)
datetuple = time.localtime(email.utils.mktime_tz(datetuple))
else:
#rtime is set, use that instead
datetuple = time.localtime(rtime)