Browse Source

Correctly handle utc timestamp for python 2.x. Backport again several things. This may be the last backport for 2.6 as the next time I'm thinking of discontinuing support instead of implementing 2.7 in 2.6... This should fix #306 and maybe #302.

pull/307/head
Florian Mounier 9 years ago
parent
commit
ee066cd148
  1. 3
      demo/moulinrouge/tests.py
  2. 27
      pygal/_compat.py
  3. 15
      pygal/test/test_date.py
  4. 2
      tox.ini

3
demo/moulinrouge/tests.py

@ -463,6 +463,7 @@ def get_test_routes(app):
chart.add(10 * '1b', [(4, 12), (5, 8), (6, 4)], secondary=True) chart.add(10 * '1b', [(4, 12), (5, 8), (6, 4)], secondary=True)
chart.add(10 * '2b', [(3, 24), (0, 17), (12, 9)], secondary=True) chart.add(10 * '2b', [(3, 24), (0, 17), (12, 9)], secondary=True)
chart.add(10 * '2', [(8, 23), (21, 1), (5, 0)]) chart.add(10 * '2', [(8, 23), (21, 1), (5, 0)])
chart.value_formatter = lambda x: str(int(x)) + '+'
return chart.render_response() return chart.render_response()
@app.route('/test/box') @app.route('/test/box')
@ -930,7 +931,7 @@ def get_test_routes(app):
(datetime(2013, 1, 12, 8), 412), (datetime(2013, 1, 12, 8), 412),
(datetime(2013, 1, 12, 8, tzinfo=tzn4), 823) (datetime(2013, 1, 12, 8, tzinfo=tzn4), 823)
]) ])
line.x_value_formatter = lambda x: x.isoformat() # strftime("%Y-%m-%d") # line.x_value_formatter = lambda x: x.isoformat() # strftime("%Y-%m-%d")
line.x_label_rotation = 45 line.x_label_rotation = 45
return line.render_response() return line.render_response()

27
pygal/_compat.py

@ -16,11 +16,12 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
from __future__ import division
"""Various hacks for transparent python 2 / python 3 support""" """Various hacks for transparent python 2 / python 3 support"""
import sys import sys
from collections import Iterable from collections import Iterable
import time from datetime import datetime, timedelta, tzinfo
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
@ -70,16 +71,32 @@ def total_seconds(td):
) / 10 ** 6 ) / 10 ** 6
return td.total_seconds() return td.total_seconds()
try:
from datetime import timezone
utc = timezone.utc
except ImportError:
class UTC(tzinfo):
def tzname(self, dt):
return 'UTC'
def utcoffset(self, dt):
return timedelta(0)
def dst(self, dt):
return None
utc = UTC()
def timestamp(x): def timestamp(x):
"""Get a timestamp from a date in python 3 and python 2""" """Get a timestamp from a date in python 3 and python 2"""
if x.tzinfo is None:
# Naive dates to utc
x = x.replace(tzinfo=utc)
if hasattr(x, 'timestamp'): if hasattr(x, 'timestamp'):
from datetime import timezone
if x.tzinfo is None:
return x.replace(tzinfo=timezone.utc).timestamp()
return x.timestamp() return x.timestamp()
else: else:
return time.mktime(x.utctimetuple()) return total_seconds(x - datetime(1970, 1, 1, tzinfo=utc))
try: try:
from urllib import quote_plus from urllib import quote_plus

15
pygal/test/test_date.py

@ -20,6 +20,7 @@
"""Date related charts tests""" """Date related charts tests"""
from pygal import DateLine, TimeLine, DateTimeLine, TimeDeltaLine from pygal import DateLine, TimeLine, DateTimeLine, TimeDeltaLine
from pygal._compat import timestamp, utc
from pygal.test.utils import texts from pygal.test.utils import texts
from datetime import datetime, date, time, timedelta from datetime import datetime, date, time, timedelta
@ -158,3 +159,17 @@ def test_date_labels():
'2013-01-01', '2013-01-01',
'2013-02-01', '2013-02-01',
'2013-03-01'] '2013-03-01']
def test_utc_timestamping():
assert timestamp(
datetime(2017, 7, 14, 2, 40).replace(tzinfo=utc)
) == 1500000000
for d in (
datetime.now(),
datetime.utcnow(),
datetime(1999, 12, 31, 23, 59, 59),
datetime(2000, 1, 1, 0, 0, 0)
):
assert datetime.utcfromtimestamp(timestamp(d)) == d

2
tox.ini

@ -14,5 +14,5 @@ setenv =
COVERAGE_FILE=.cov-{envname} COVERAGE_FILE=.cov-{envname}
commands = commands =
coverage run --source=pygal {envbindir}/py.test pygal/test --junitxml=junit-{envname}.xml --flake8 coverage run --source=pygal {envbindir}/py.test {posargs:pygal/test} --junitxml=junit-{envname}.xml --flake8
coverage xml -o coverage-{envname}.xml coverage xml -o coverage-{envname}.xml

Loading…
Cancel
Save