From 78b177233d29defbcc1a01925da5be087fe52d66 Mon Sep 17 00:00:00 2001 From: Vincent Driessen Date: Sat, 23 Aug 2014 13:18:45 +0200 Subject: Reimplement times on top of Arrow. --- setup.py | 2 +- tests/test_times.py | 99 +++++++++++++++++------------------------------------ times/__init__.py | 53 +++++++++------------------- tox.ini | 2 +- 4 files changed, 51 insertions(+), 105 deletions(-) diff --git a/setup.py b/setup.py index b382418..cc878b0 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( include_package_data=True, zip_safe=False, platforms='any', - install_requires=['arrow', 'pytz >= 0a', 'python-dateutil >= 2.1'], + install_requires=['arrow'], classifiers=[ # As from http://pypi.python.org/pypi?%3Aaction=list_classifiers #'Development Status :: 1 - Planning', diff --git a/tests/test_times.py b/tests/test_times.py index f308475..34e5247 100644 --- a/tests/test_times.py +++ b/tests/test_times.py @@ -2,10 +2,11 @@ try: import unittest2 as unittest except ImportError: import unittest # noqa -import times -import pytz from datetime import datetime +import pytz +import times + class TestTimes(unittest.TestCase): def setUp(self): @@ -16,39 +17,29 @@ class TestTimes(unittest.TestCase): self.time_in_ams = ams.localize(datetime(2012, 2, 1, 12, 56, 31)) self.sometime_univ = datetime(2012, 2, 1, 11, 56, 31) - - # now() def test_now(self): # noqa """times.now() has no attached timezone info""" now = times.now() self.assertIsNone(now.tzinfo) - - # to_universal() def test_to_universal_with_tzinfo(self): # noqa """Convert local dates with timezone info to universal date""" ny_time = self.time_in_ny ams_time = self.time_in_ams - self.assertEquals( - times.to_universal(ny_time), - self.sometime_univ) - self.assertEquals( - times.to_universal(ams_time), - self.sometime_univ) + self.assertEquals(times.to_universal(ny_time), + self.sometime_univ) + self.assertEquals(times.to_universal(ams_time), + self.sometime_univ) self.assertEquals(ny_time.hour, 6) - self.assertEquals( - times.to_universal(ny_time).hour, 11) + self.assertEquals(times.to_universal(ny_time).hour, 11) self.assertEquals(ams_time.hour, 12) - self.assertEquals( - times.to_universal(ams_time).hour, 11) + self.assertEquals(times.to_universal(ams_time).hour, 11) # Test alias from_local, too - self.assertEquals( - times.from_local(ny_time), - self.sometime_univ) + self.assertEquals(times.from_local(ny_time), self.sometime_univ) def test_to_universal_without_tzinfo(self): """Convert local dates without timezone info to universal date""" @@ -59,15 +50,13 @@ class TestTimes(unittest.TestCase): ams_time = self.time_in_ams.replace(tzinfo=None) # When time has no tzinfo attached, it should be specified explicitly - est = pytz.timezone('EST') - self.assertEquals( - times.to_universal(ny_time, est), - self.sometime_univ) + est = 'EST' + self.assertEquals(times.to_universal(ny_time, est), + self.sometime_univ) # ...or simply with a string - self.assertEquals( - times.to_universal(ams_time, 'Europe/Amsterdam'), - self.sometime_univ) + self.assertEquals(times.to_universal(ams_time, 'Europe/Amsterdam'), + self.sometime_univ) def test_to_universal_with_unix_timestamp(self): """Convert UNIX timestamps to universal date""" @@ -86,30 +75,18 @@ class TestTimes(unittest.TestCase): self.assertEquals(dt, times.to_universal('2012-02-01 06:56:31-05:00')) # Timezone-less strings require explicit source timezone - self.assertEquals(dt, times.to_universal('2012-02-02 00:56:31', - 'Pacific/Auckland')) + self.assertEquals(dt, times.to_universal('2012-02-02 00:56:31', 'Pacific/Auckland')) self.assertEquals(dt, times.to_universal('2012-02-01 12:56:31', 'CET')) self.assertEquals(dt, times.to_universal('2012-02-01 06:56:31', 'EST')) - # Timezone-less strings are rejected if source timezone is not - # specified - with self.assertRaises(ValueError): - self.assertEquals(dt, times.to_universal('2012-02-01 12:56:31')) - - - def test_to_universal_rejects_no_tzinfo(self): # noqa - """Converting to universal times requires source timezone""" - now = datetime.now() - with self.assertRaises(ValueError): - times.to_universal(now) + # Without a timezone, UTC is assumed + self.assertEquals(dt, times.to_universal('2012-02-01 11:56:31')) def test_to_universal_rejects_non_date_arguments(self): """to_universal rejects non-date arguments""" with self.assertRaises(TypeError): times.to_universal([1, 2, 3]) - - # from_unix() def test_convert_unix_time_to_datetime(self): # noqa """Can convert from UNIX time to universal time.""" unix_time = 1328257004.456 # as returned by time.time() @@ -133,8 +110,6 @@ class TestTimes(unittest.TestCase): with self.assertRaises(TypeError): times.from_unix('lol') - - # to_unix() def test_convert_datetime_to_unix_time(self): # noqa """Can convert UNIX time to universal time.""" self.assertEquals( @@ -147,52 +122,44 @@ class TestTimes(unittest.TestCase): with self.assertRaises(TypeError): times.to_unix('lol') - - # to_local() def test_convert_universal_to_local(self): # noqa """Convert universal time to local time""" univ = self.sometime_univ - self.assertEquals( - times.to_local(univ, pytz.timezone('Europe/Amsterdam')), - self.time_in_ams) - self.assertEquals( - times.to_local(univ, pytz.timezone('EST')), - self.time_in_ny) + self.assertEquals(times.to_local(univ, 'Europe/Amsterdam'), + self.time_in_ams) + self.assertEquals(times.to_local(univ, 'EST'), + self.time_in_ny) def test_convert_refuses_local_to_local(self): """Refuses to convert between timezones directly""" loc = self.time_in_ams with self.assertRaises(ValueError): - times.to_local(loc, pytz.timezone('Europe/Amsterdam')) + times.to_local(loc, 'Europe/Amsterdam') - - # format() def test_format_without_tzinfo(self): # noqa """Format times without timezone info""" dt = self.sometime_univ - auckland = pytz.timezone('Pacific/Auckland') - est = pytz.timezone('EST') - ams = pytz.timezone('Europe/Amsterdam') + auckland = 'Pacific/Auckland' + est = 'EST' + ams = 'Europe/Amsterdam' self.assertEquals(times.format(dt, auckland), - '2012-02-02T00:56:31+13:00') + '2012-02-02T00:56:31+13:00') self.assertEquals(times.format(dt, ams), '2012-02-01T12:56:31+01:00') self.assertEquals(times.format(dt, est), '2012-02-01T06:56:31-05:00') def test_custom_format(self): dt = self.sometime_univ - auckland = pytz.timezone('Pacific/Auckland') - est = pytz.timezone('EST') + auckland = 'Pacific/Auckland' + est = 'EST' self.assertEquals(times.format(dt, auckland, '%H'), '00') self.assertEquals(times.format(dt, est, '%H'), '06') def test_format_refuses_local_times(self): """Format refuses local time input""" - auckland = pytz.timezone('Pacific/Auckland') + auckland = 'Pacific/Auckland' with self.assertRaises(ValueError): times.format(self.time_in_ams, auckland) - - # from/to unix and back def test_convert_between_unix_times(self): # noqa """Can convert UNIX time to universal time and back.""" given_unix = 1328257004.456 # as returned by time.time() @@ -202,7 +169,5 @@ class TestTimes(unittest.TestCase): ) given_dt = self.sometime_univ - self.assertEquals( - times.from_unix(times.to_unix(given_dt)), - given_dt - ) + self.assertEquals(times.from_unix(times.to_unix(given_dt)), + given_dt) diff --git a/times/__init__.py b/times/__init__.py index 8748964..15fd0cb 100644 --- a/times/__init__.py +++ b/times/__init__.py @@ -1,10 +1,7 @@ import datetime -import calendar import sys -import pytz -from dateutil.parser import parse - +import arrow from .version import VERSION @@ -20,17 +17,16 @@ __version__ = VERSION def to_universal(local_dt, timezone=None): - """Converts the given local datetime or UNIX timestamp to a universal + """ + Converts the given local datetime or UNIX timestamp to a universal datetime. """ if isinstance(local_dt, (int, float)): if timezone is not None: - raise ValueError( - 'Timezone argument illegal when using UNIX timestamps.' - ) + raise ValueError('Timezone argument illegal when using UNIX timestamps.') return from_unix(local_dt) elif isinstance(local_dt, string_types): - local_dt = parse(local_dt) + local_dt = arrow.get(local_dt).to('UTC').naive return from_local(local_dt, timezone) @@ -40,46 +36,33 @@ def from_local(local_dt, timezone=None): if not isinstance(local_dt, datetime.datetime): raise TypeError('Expected a datetime object') - if timezone is not None: - if local_dt.tzinfo is not None: - raise ValueError( - 'Cannot use timezone-aware datetime with explicit timezone ' - 'argument.' - ) - - if isinstance(timezone, string_types): - timezone = pytz.timezone(timezone) - dt_with_tzinfo = timezone.localize(local_dt) + if timezone is None: + a = arrow.get(local_dt) else: - if local_dt.tzinfo is None: - raise ValueError( - 'Explicit timezone required to convert naive datetimes.' - ) - dt_with_tzinfo = local_dt - univ_dt = dt_with_tzinfo.astimezone(pytz.utc) - return univ_dt.replace(tzinfo=None) + a = arrow.get(local_dt, timezone) + return a.to('UTC').naive def from_unix(ut): - """Converts a UNIX timestamp, as returned by `time.time()`, to universal + """ + Converts a UNIX timestamp, as returned by `time.time()`, to universal time. Assumes the input is in UTC, as `time.time()` does. """ if not isinstance(ut, (int, float)): raise TypeError('Expected an int or float value') - return datetime.datetime.utcfromtimestamp(float(ut)) + return arrow.get(ut).naive def to_local(dt, timezone): - """Converts universal datetime to a local representation in given timezone. - """ + """Converts universal datetime to a local representation in given timezone.""" if dt.tzinfo is not None: raise ValueError( 'First argument to to_local() should be a universal time.' ) - if isinstance(timezone, string_types): - timezone = pytz.timezone(timezone) - return pytz.utc.localize(dt).astimezone(timezone) + if not isinstance(timezone, string_types): + raise TypeError('expected a timezone name (string), but got {} instead'.format(type(timezone))) + return arrow.get(dt).to(timezone).datetime def to_unix(dt): @@ -87,13 +70,11 @@ def to_unix(dt): if not isinstance(dt, datetime.datetime): raise TypeError('Expected a datetime object') - return calendar.timegm(dt.utctimetuple()) + return arrow.get(dt).timestamp def format(dt, timezone, fmt=None): """Formats the given universal time for display in the given time zone.""" - if timezone is None: - raise ValueError('Please give an explicit timezone.') local = to_local(dt, timezone) if fmt is None: return local.isoformat() diff --git a/tox.ini b/tox.ini index 01fa453..2e7da45 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ envlist = py26,py27,py33,py34,pypy deps = nose coverage -commands = nosetests --with-coverage --cover-erase --cover-package=times +commands = nosetests --with-coverage --cover-erase --cover-package=times {posargs} [testenv:py26] deps = -- cgit v1.2.1