diff --git a/tornado/httputil.py b/tornado/httputil.py index 36d7dc8f..3d17b610 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -18,8 +18,10 @@ from __future__ import absolute_import, division, print_function, with_statement +import calendar import collections import datetime +import email.utils import numbers import re import time @@ -382,15 +384,15 @@ def format_timestamp(ts): >>> format_timestamp(1359312200) 'Sun, 27 Jan 2013 18:43:20 GMT' """ - if isinstance(ts, (tuple, time.struct_time)): + if isinstance(ts, numbers.Real): pass + elif isinstance(ts, (tuple, time.struct_time)): + ts = calendar.timegm(ts) elif isinstance(ts, datetime.datetime): - ts = ts.utctimetuple() - elif isinstance(ts, numbers.Real): - ts = time.gmtime(ts) + ts = calendar.timegm(ts.utctimetuple()) else: raise TypeError("unknown timestamp type: %r" % ts) - return time.strftime("%a, %d %b %Y %H:%M:%S GMT", ts) + return email.utils.formatdate(ts, usegmt=True) # _parseparam and _parse_header are copied and modified from python2.7's cgi.py # The original 2.7 version of this code did not correctly support some diff --git a/tornado/test/runtests.py b/tornado/test/runtests.py index 22cda522..1f4c08c9 100644 --- a/tornado/test/runtests.py +++ b/tornado/test/runtests.py @@ -2,6 +2,7 @@ from __future__ import absolute_import, division, print_function, with_statement import gc +import locale # system locale module, not tornado.locale import logging import operator import textwrap @@ -95,6 +96,8 @@ if __name__ == '__main__': "e.g. DEBUG_STATS or DEBUG_COLLECTABLE,DEBUG_OBJECTS", callback=lambda values: gc.set_debug( reduce(operator.or_, (getattr(gc, v) for v in values)))) + define('locale', type=str, default=None, + callback=lambda x: locale.setlocale(locale.LC_ALL, x)) def configure_ioloop(): kwargs = {} diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 74eec11e..d3884393 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -13,6 +13,7 @@ from tornado.web import RequestHandler, authenticated, Application, asynchronous import binascii import datetime +import email.utils import logging import os import re @@ -1160,8 +1161,8 @@ class DateHeaderTest(SimpleHandlerTestCase): def test_date_header(self): response = self.fetch('/') - header_date = datetime.datetime.strptime(response.headers['Date'], - "%a, %d %b %Y %H:%M:%S GMT") + header_date = datetime.datetime( + *email.utils.parsedate(response.headers['Date'])[:6]) self.assertTrue(header_date - datetime.datetime.utcnow() < datetime.timedelta(seconds=2)) diff --git a/tornado/web.py b/tornado/web.py index 2ede8d32..f670d8aa 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -239,7 +239,7 @@ class RequestHandler(object): self._headers = httputil.HTTPHeaders({ "Server": "TornadoServer/%s" % tornado.version, "Content-Type": "text/html; charset=UTF-8", - "Date": httputil.format_timestamp(time.gmtime()), + "Date": httputil.format_timestamp(time.time()), }) self.set_default_headers() if (not self.request.supports_http_1_1() and diff --git a/tox.ini b/tox.ini index 95ab47af..3d143c3a 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ [tox] # "-full" variants include optional dependencies, to ensure # that things work both in a bare install and with all the extras. -envlist = py27-full, py27-curl, py32-full, pypy, py26, py26-full, py27, py32, py32-utf8, py33, py27-opt, py32-opt, pypy-full, py27-select, py27-monotonic, py33-monotonic, py27-twisted, py27-threadedresolver, py27-twistedresolver, py27-twistedlayered, py27-caresresolver, py32-caresresolver, py27-docs +envlist = py27-full, py27-curl, py32-full, pypy, py26, py26-full, py27, py32, py32-utf8, py33, py27-opt, py32-opt, pypy-full, py27-select, py27-monotonic, py33-monotonic, py27-twisted, py27-threadedresolver, py27-twistedresolver, py27-twistedlayered, py27-caresresolver, py32-caresresolver, py27-locale, py27-docs [testenv] commands = python -m tornado.test.runtests {posargs:} @@ -138,6 +138,10 @@ deps = twisted commands = python -m tornado.test.runtests --resolver=tornado.platform.caresresolver.CaresResolver {posargs:} +[testenv:py27-locale] +basepython = python2.7 +commands = python -m tornado.test.runtests --locale=zh_TW {posargs:} + [testenv:pypy-full] # This configuration works with pypy 1.9. pycurl installs ok but # curl_httpclient doesn't work. Twisted works most of the time, but