summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Belopolsky <alexander.belopolsky@gmail.com>2012-06-23 01:03:39 (GMT)
committerAlexander Belopolsky <alexander.belopolsky@gmail.com>2012-06-23 01:03:39 (GMT)
commit8141cc7f8895778a430c4c8a65c65310e3c6afe7 (patch)
tree97468b29a67c9e3048815eb89ece3bfde2fe199b
parent60c13ddd9b03cb28f454e37ddb1214d4ae4f5e82 (diff)
downloadcpython-8141cc7f8895778a430c4c8a65c65310e3c6afe7.zip
cpython-8141cc7f8895778a430c4c8a65c65310e3c6afe7.tar.gz
cpython-8141cc7f8895778a430c4c8a65c65310e3c6afe7.tar.bz2
Issues #11024: Fixes and additional tests for Time2Internaldate.
-rw-r--r--Doc/library/imaplib.rst16
-rw-r--r--Lib/imaplib.py45
-rw-r--r--Lib/test/test_imaplib.py34
-rw-r--r--Misc/NEWS2
4 files changed, 62 insertions, 35 deletions
diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst
index 038355c..fefb284 100644
--- a/Doc/library/imaplib.rst
+++ b/Doc/library/imaplib.rst
@@ -113,13 +113,15 @@ The following utility functions are defined:
.. function:: Time2Internaldate(date_time)
- Convert *date_time* to an IMAP4 ``INTERNALDATE`` representation. The
- return value is a string in the form: ``"DD-Mmm-YYYY HH:MM:SS
- +HHMM"`` (including double-quotes). The *date_time* argument can be a
- number (int or float) representing seconds since epoch (as returned
- by :func:`time.time`), a 9-tuple representing local time (as returned by
- :func:`time.localtime`), or a double-quoted string. In the last case, it
- is assumed to already be in the correct format.
+ Convert *date_time* to an IMAP4 ``INTERNALDATE`` representation.
+ The return value is a string in the form: ``"DD-Mmm-YYYY HH:MM:SS
+ +HHMM"`` (including double-quotes). The *date_time* argument can
+ be a number (int or float) representing seconds since epoch (as
+ returned by :func:`time.time`), a 9-tuple representing local time
+ an instance of :class:`time.struct_time` (as returned by
+ :func:`time.localtime`), an aware instance of
+ :class:`datetime.datetime`, or a double-quoted string. In the last
+ case, it is assumed to already be in the correct format.
Note that IMAP4 message numbers change as the mailbox changes; in particular,
after an ``EXPUNGE`` command performs deletions the remaining messages are
diff --git a/Lib/imaplib.py b/Lib/imaplib.py
index 681c7cf..e16fb95 100644
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -23,7 +23,7 @@ Public functions: Internaldate2tuple
__version__ = "2.58"
import binascii, errno, random, re, socket, subprocess, sys, time, calendar
-
+from datetime import datetime, timezone, timedelta
try:
import ssl
HAVE_SSL = True
@@ -1313,10 +1313,8 @@ class _Authenticator:
return ''
return binascii.a2b_base64(inp)
-
-
-Mon2num = {b'Jan': 1, b'Feb': 2, b'Mar': 3, b'Apr': 4, b'May': 5, b'Jun': 6,
- b'Jul': 7, b'Aug': 8, b'Sep': 9, b'Oct': 10, b'Nov': 11, b'Dec': 12}
+Months = ' Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ')
+Mon2num = {s.encode():n+1 for n, s in enumerate(Months[1:])}
def Internaldate2tuple(resp):
"""Parse an IMAP4 INTERNALDATE string.
@@ -1384,28 +1382,37 @@ def Time2Internaldate(date_time):
Return string in form: '"DD-Mmm-YYYY HH:MM:SS +HHMM"'. The
date_time argument can be a number (int or float) representing
seconds since epoch (as returned by time.time()), a 9-tuple
- representing local time (as returned by time.localtime()), or a
+ representing local time, an instance of time.struct_time (as
+ returned by time.localtime()), an aware datetime instance or a
double-quoted string. In the last case, it is assumed to already
be in the correct format.
"""
-
if isinstance(date_time, (int, float)):
- tt = time.localtime(date_time)
- elif isinstance(date_time, (tuple, time.struct_time)):
- tt = date_time
+ dt = datetime.fromtimestamp(date_time,
+ timezone.utc).astimezone()
+ elif isinstance(date_time, tuple):
+ try:
+ gmtoff = date_time.tm_gmtoff
+ except AttributeError:
+ if time.daylight:
+ dst = date_time[8]
+ if dst == -1:
+ dst = time.localtime(time.mktime(date_time))[8]
+ gmtoff = -(time.timezone, time.altzone)[dst]
+ else:
+ gmtoff = -time.timezone
+ delta = timedelta(seconds=gmtoff)
+ dt = datetime(*date_time[:6], tzinfo=timezone(delta))
+ elif isinstance(date_time, datetime):
+ if date_time.tzinfo is None:
+ raise ValueError("date_time must be aware")
+ dt = date_time
elif isinstance(date_time, str) and (date_time[0],date_time[-1]) == ('"','"'):
return date_time # Assume in correct format
else:
raise ValueError("date_time not of a known type")
-
- dt = time.strftime("%d-%b-%Y %H:%M:%S", tt)
- if dt[0] == '0':
- dt = ' ' + dt[1:]
- if time.daylight and tt[-1]:
- zone = -time.altzone
- else:
- zone = -time.timezone
- return '"' + dt + " %+03d%02d" % divmod(zone//60, 60) + '"'
+ fmt = '"%d-{}-%Y %H:%M:%S %z"'.format(Months[dt.month])
+ return dt.strftime(fmt)
diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
index e629cb1..bfb9006 100644
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -11,9 +11,9 @@ import socketserver
import time
import calendar
-from test.support import reap_threads, verbose, transient_internet, run_with_tz
+from test.support import reap_threads, verbose, transient_internet, run_with_tz, run_with_locale
import unittest
-
+from datetime import datetime, timezone, timedelta
try:
import ssl
except ImportError:
@@ -43,14 +43,30 @@ class TestImaplib(unittest.TestCase):
imaplib.Internaldate2tuple(
b'25 (INTERNALDATE "02-Apr-2000 03:30:00 +0000")'))
- def test_that_Time2Internaldate_returns_a_result(self):
- # We can check only that it successfully produces a result,
- # not the correctness of the result itself, since the result
- # depends on the timezone the machine is in.
- timevalues = [2000000000, 2000000000.0, time.localtime(2000000000),
- '"18-May-2033 05:33:20 +0200"']
- for t in timevalues:
+
+ def timevalues(self):
+ return [2000000000, 2000000000.0, time.localtime(2000000000),
+ (2033, 5, 18, 5, 33, 20, -1, -1, -1),
+ (2033, 5, 18, 5, 33, 20, -1, -1, 1),
+ datetime.fromtimestamp(2000000000,
+ timezone(timedelta(0, 2*60*60))),
+ '"18-May-2033 05:33:20 +0200"']
+
+ @run_with_locale('LC_ALL', 'de_DE', 'fr_FR')
+ @run_with_tz('STD-1DST')
+ def test_Time2Internaldate(self):
+ expected = '"18-May-2033 05:33:20 +0200"'
+
+ for t in self.timevalues():
+ internal = imaplib.Time2Internaldate(t)
+ self.assertEqual(internal, expected)
+
+ def test_that_Time2Internaldate_returns_a_result(self):
+ # Without tzset, we can check only that it successfully
+ # produces a result, not the correctness of the result itself,
+ # since the result depends on the timezone the machine is in.
+ for t in self.timevalues():
imaplib.Time2Internaldate(t)
diff --git a/Misc/NEWS b/Misc/NEWS
index 373b04b..b6f735f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -40,6 +40,8 @@ Core and Builtins
Library
-------
+- Issues #11024: Fixes and additional tests for Time2Internaldate.
+
- Issue #14626: Large refactoring of functions / parameters in the os module.
Many functions now support "dir_fd" and "follow_symlinks" parameters;
some also support accepting an open file descriptor in place of of a path