diff options
| -rw-r--r-- | openstack/common/timeutils.py | 73 | ||||
| -rw-r--r-- | openstack/common/utils.py | 49 | ||||
| -rw-r--r-- | tests/unit/test_timeutils.py | 157 | ||||
| -rw-r--r-- | tests/unit/test_utils.py | 131 |
4 files changed, 230 insertions, 180 deletions
diff --git a/openstack/common/timeutils.py b/openstack/common/timeutils.py new file mode 100644 index 0000000..c536cb2 --- /dev/null +++ b/openstack/common/timeutils.py @@ -0,0 +1,73 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Time related utilities and helper functions. +""" + +import datetime + +import iso8601 + + +TIME_FORMAT = "%Y-%m-%dT%H:%M:%S" + + +def isotime(at=None): + """Stringify time in ISO 8601 format""" + if not at: + at = datetime.datetime.utcnow() + str = at.strftime(TIME_FORMAT) + tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' + str += ('Z' if tz == 'UTC' else tz) + return str + + +def parse_isotime(timestr): + """Parse time from ISO 8601 format""" + try: + return iso8601.parse_date(timestr) + except iso8601.ParseError as e: + raise ValueError(e.message) + except TypeError as e: + raise ValueError(e.message) + + +def normalize_time(timestamp): + """Normalize time in arbitrary timezone to UTC""" + offset = timestamp.utcoffset() + return timestamp.replace(tzinfo=None) - offset if offset else timestamp + + +def utcnow(): + """Overridable version of utils.utcnow.""" + if utcnow.override_time: + return utcnow.override_time + return datetime.datetime.utcnow() + + +utcnow.override_time = None + + +def set_time_override(override_time=datetime.datetime.utcnow()): + """Override utils.utcnow to return a constant time.""" + utcnow.override_time = override_time + + +def clear_time_override(): + """Remove the overridden time.""" + utcnow.override_time = None diff --git a/openstack/common/utils.py b/openstack/common/utils.py index 0191036..d3d01fa 100644 --- a/openstack/common/utils.py +++ b/openstack/common/utils.py @@ -19,7 +19,6 @@ System-level utilities and helper functions. """ -import datetime import logging import os import random @@ -28,12 +27,10 @@ import sys from eventlet import greenthread from eventlet.green import subprocess -import iso8601 from openstack.common import exception -TIME_FORMAT = "%Y-%m-%dT%H:%M:%S" LOG = logging.getLogger(__name__) @@ -163,52 +160,6 @@ def import_object(import_str): return import_class(import_str) -def isotime(at=None): - """Stringify time in ISO 8601 format""" - if not at: - at = datetime.datetime.utcnow() - str = at.strftime(TIME_FORMAT) - tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - str += ('Z' if tz == 'UTC' else tz) - return str - - -def parse_isotime(timestr): - """Parse time from ISO 8601 format""" - try: - return iso8601.parse_date(timestr) - except iso8601.ParseError as e: - raise ValueError(e.message) - except TypeError as e: - raise ValueError(e.message) - - -def normalize_time(timestamp): - """Normalize time in arbitrary timezone to UTC""" - offset = timestamp.utcoffset() - return timestamp.replace(tzinfo=None) - offset if offset else timestamp - - -def utcnow(): - """Overridable version of utils.utcnow.""" - if utcnow.override_time: - return utcnow.override_time - return datetime.datetime.utcnow() - - -utcnow.override_time = None - - -def set_time_override(override_time=datetime.datetime.utcnow()): - """Override utils.utcnow to return a constant time.""" - utcnow.override_time = override_time - - -def clear_time_override(): - """Remove the overridden time.""" - utcnow.override_time = None - - def auth_str_equal(provided, known): """Constant-time string comparison. diff --git a/tests/unit/test_timeutils.py b/tests/unit/test_timeutils.py new file mode 100644 index 0000000..59a5032 --- /dev/null +++ b/tests/unit/test_timeutils.py @@ -0,0 +1,157 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import datetime +import unittest + +import iso8601 +import mock + +from openstack.common import timeutils + + +class TimeUtilsTest(unittest.TestCase): + + def test_isotime(self): + skynet_self_aware_time_str = '1997-08-29T06:14:00Z' + skynet_self_aware_time = datetime.datetime(1997, 8, 29, 6, 14, 0, + tzinfo=iso8601.iso8601.UTC) + with mock.patch('datetime.datetime') as datetime_mock: + datetime_mock.utcnow.return_value = skynet_self_aware_time + dt = timeutils.isotime() + self.assertEqual(dt, skynet_self_aware_time_str) + + def test_parse_isotime(self): + skynet_self_aware_time_str = '1997-08-29T06:14:00Z' + skynet_self_aware_time = datetime.datetime(1997, 8, 29, 6, 14, 0, + tzinfo=iso8601.iso8601.UTC) + self.assertEqual(skynet_self_aware_time, + timeutils.parse_isotime(skynet_self_aware_time_str)) + + def test_utcnow(self): + timeutils.set_time_override(mock.sentinel.utcnow) + self.assertEqual(timeutils.utcnow(), mock.sentinel.utcnow) + + timeutils.clear_time_override() + self.assertFalse(timeutils.utcnow() == mock.sentinel.utcnow) + + self.assertTrue(timeutils.utcnow()) + + +class TestIso8601Time(unittest.TestCase): + + def _instaneous(self, timestamp, yr, mon, day, hr, min, sec, micro): + self.assertEquals(timestamp.year, yr) + self.assertEquals(timestamp.month, mon) + self.assertEquals(timestamp.day, day) + self.assertEquals(timestamp.hour, hr) + self.assertEquals(timestamp.minute, min) + self.assertEquals(timestamp.second, sec) + self.assertEquals(timestamp.microsecond, micro) + + def _do_test(self, str, yr, mon, day, hr, min, sec, micro, shift): + DAY_SECONDS = 24 * 60 * 60 + timestamp = timeutils.parse_isotime(str) + self._instaneous(timestamp, yr, mon, day, hr, min, sec, micro) + offset = timestamp.tzinfo.utcoffset(None) + self.assertEqual(offset.seconds + offset.days * DAY_SECONDS, shift) + + def test_zulu(self): + str = '2012-02-14T20:53:07Z' + self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, 0) + + def test_zulu_micros(self): + str = '2012-02-14T20:53:07.123Z' + self._do_test(str, 2012, 02, 14, 20, 53, 7, 123000, 0) + + def test_offset_east(self): + str = '2012-02-14T20:53:07+04:30' + offset = 4.5 * 60 * 60 + self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) + + def test_offset_east_micros(self): + str = '2012-02-14T20:53:07.42+04:30' + offset = 4.5 * 60 * 60 + self._do_test(str, 2012, 02, 14, 20, 53, 7, 420000, offset) + + def test_offset_west(self): + str = '2012-02-14T20:53:07-05:30' + offset = -5.5 * 60 * 60 + self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) + + def test_offset_west_micros(self): + str = '2012-02-14T20:53:07.654321-05:30' + offset = -5.5 * 60 * 60 + self._do_test(str, 2012, 02, 14, 20, 53, 7, 654321, offset) + + def test_compare(self): + zulu = timeutils.parse_isotime('2012-02-14T20:53:07') + east = timeutils.parse_isotime('2012-02-14T20:53:07-01:00') + west = timeutils.parse_isotime('2012-02-14T20:53:07+01:00') + self.assertTrue(east > west) + self.assertTrue(east > zulu) + self.assertTrue(zulu > west) + + def test_compare_micros(self): + zulu = timeutils.parse_isotime('2012-02-14T20:53:07.6544') + east = timeutils.parse_isotime('2012-02-14T19:53:07.654321-01:00') + west = timeutils.parse_isotime('2012-02-14T21:53:07.655+01:00') + self.assertTrue(east < west) + self.assertTrue(east < zulu) + self.assertTrue(zulu < west) + + def test_zulu_roundtrip(self): + str = '2012-02-14T20:53:07Z' + zulu = timeutils.parse_isotime(str) + self.assertEquals(zulu.tzinfo, iso8601.iso8601.UTC) + self.assertEquals(timeutils.isotime(zulu), str) + + def test_east_roundtrip(self): + str = '2012-02-14T20:53:07-07:00' + east = timeutils.parse_isotime(str) + self.assertEquals(east.tzinfo.tzname(None), '-07:00') + self.assertEquals(timeutils.isotime(east), str) + + def test_west_roundtrip(self): + str = '2012-02-14T20:53:07+11:30' + west = timeutils.parse_isotime(str) + self.assertEquals(west.tzinfo.tzname(None), '+11:30') + self.assertEquals(timeutils.isotime(west), str) + + def test_now_roundtrip(self): + str = timeutils.isotime() + now = timeutils.parse_isotime(str) + self.assertEquals(now.tzinfo, iso8601.iso8601.UTC) + self.assertEquals(timeutils.isotime(now), str) + + def test_zulu_normalize(self): + str = '2012-02-14T20:53:07Z' + zulu = timeutils.parse_isotime(str) + normed = timeutils.normalize_time(zulu) + self._instaneous(normed, 2012, 2, 14, 20, 53, 07, 0) + + def test_east_normalize(self): + str = '2012-02-14T20:53:07-07:00' + east = timeutils.parse_isotime(str) + normed = timeutils.normalize_time(east) + self._instaneous(normed, 2012, 2, 15, 03, 53, 07, 0) + + def test_west_normalize(self): + str = '2012-02-14T20:53:07+21:00' + west = timeutils.parse_isotime(str) + normed = timeutils.normalize_time(west) + self._instaneous(normed, 2012, 2, 13, 23, 53, 07, 0) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index bf6edba..bf015b5 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -19,7 +19,6 @@ import datetime import sys import unittest -import iso8601 import mock from openstack.common import exception @@ -103,138 +102,8 @@ class UtilsTest(unittest.TestCase): dt = utils.import_object('datetime.datetime') self.assertEqual(sys.modules['datetime'].datetime, dt) - def test_isotime(self): - skynet_self_aware_time_str = '1997-08-29T06:14:00Z' - skynet_self_aware_time = datetime.datetime(1997, 8, 29, 6, 14, 0, - tzinfo=iso8601.iso8601.UTC) - with mock.patch('datetime.datetime') as datetime_mock: - datetime_mock.utcnow.return_value = skynet_self_aware_time - dt = utils.isotime() - self.assertEqual(dt, skynet_self_aware_time_str) - - def test_parse_isotime(self): - skynet_self_aware_time_str = '1997-08-29T06:14:00Z' - skynet_self_aware_time = datetime.datetime(1997, 8, 29, 6, 14, 0, - tzinfo=iso8601.iso8601.UTC) - self.assertEqual(skynet_self_aware_time, - utils.parse_isotime(skynet_self_aware_time_str)) - - def test_utcnow(self): - utils.set_time_override(mock.sentinel.utcnow) - self.assertEqual(utils.utcnow(), mock.sentinel.utcnow) - - utils.clear_time_override() - self.assertFalse(utils.utcnow() == mock.sentinel.utcnow) - - self.assertTrue(utils.utcnow()) - def test_auth_str_equal(self): self.assertTrue(utils.auth_str_equal('abc123', 'abc123')) self.assertFalse(utils.auth_str_equal('a', 'aaaaa')) self.assertFalse(utils.auth_str_equal('aaaaa', 'a')) self.assertFalse(utils.auth_str_equal('ABC123', 'abc123')) - - -class TestIso8601Time(unittest.TestCase): - - def _instaneous(self, timestamp, yr, mon, day, hr, min, sec, micro): - self.assertEquals(timestamp.year, yr) - self.assertEquals(timestamp.month, mon) - self.assertEquals(timestamp.day, day) - self.assertEquals(timestamp.hour, hr) - self.assertEquals(timestamp.minute, min) - self.assertEquals(timestamp.second, sec) - self.assertEquals(timestamp.microsecond, micro) - - def _do_test(self, str, yr, mon, day, hr, min, sec, micro, shift): - DAY_SECONDS = 24 * 60 * 60 - timestamp = utils.parse_isotime(str) - self._instaneous(timestamp, yr, mon, day, hr, min, sec, micro) - offset = timestamp.tzinfo.utcoffset(None) - self.assertEqual(offset.seconds + offset.days * DAY_SECONDS, shift) - - def test_zulu(self): - str = '2012-02-14T20:53:07Z' - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, 0) - - def test_zulu_micros(self): - str = '2012-02-14T20:53:07.123Z' - self._do_test(str, 2012, 02, 14, 20, 53, 7, 123000, 0) - - def test_offset_east(self): - str = '2012-02-14T20:53:07+04:30' - offset = 4.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) - - def test_offset_east_micros(self): - str = '2012-02-14T20:53:07.42+04:30' - offset = 4.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 420000, offset) - - def test_offset_west(self): - str = '2012-02-14T20:53:07-05:30' - offset = -5.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 0, offset) - - def test_offset_west_micros(self): - str = '2012-02-14T20:53:07.654321-05:30' - offset = -5.5 * 60 * 60 - self._do_test(str, 2012, 02, 14, 20, 53, 7, 654321, offset) - - def test_compare(self): - zulu = utils.parse_isotime('2012-02-14T20:53:07') - east = utils.parse_isotime('2012-02-14T20:53:07-01:00') - west = utils.parse_isotime('2012-02-14T20:53:07+01:00') - self.assertTrue(east > west) - self.assertTrue(east > zulu) - self.assertTrue(zulu > west) - - def test_compare_micros(self): - zulu = utils.parse_isotime('2012-02-14T20:53:07.6544') - east = utils.parse_isotime('2012-02-14T19:53:07.654321-01:00') - west = utils.parse_isotime('2012-02-14T21:53:07.655+01:00') - self.assertTrue(east < west) - self.assertTrue(east < zulu) - self.assertTrue(zulu < west) - - def test_zulu_roundtrip(self): - str = '2012-02-14T20:53:07Z' - zulu = utils.parse_isotime(str) - self.assertEquals(zulu.tzinfo, iso8601.iso8601.UTC) - self.assertEquals(utils.isotime(zulu), str) - - def test_east_roundtrip(self): - str = '2012-02-14T20:53:07-07:00' - east = utils.parse_isotime(str) - self.assertEquals(east.tzinfo.tzname(None), '-07:00') - self.assertEquals(utils.isotime(east), str) - - def test_west_roundtrip(self): - str = '2012-02-14T20:53:07+11:30' - west = utils.parse_isotime(str) - self.assertEquals(west.tzinfo.tzname(None), '+11:30') - self.assertEquals(utils.isotime(west), str) - - def test_now_roundtrip(self): - str = utils.isotime() - now = utils.parse_isotime(str) - self.assertEquals(now.tzinfo, iso8601.iso8601.UTC) - self.assertEquals(utils.isotime(now), str) - - def test_zulu_normalize(self): - str = '2012-02-14T20:53:07Z' - zulu = utils.parse_isotime(str) - normed = utils.normalize_time(zulu) - self._instaneous(normed, 2012, 2, 14, 20, 53, 07, 0) - - def test_east_normalize(self): - str = '2012-02-14T20:53:07-07:00' - east = utils.parse_isotime(str) - normed = utils.normalize_time(east) - self._instaneous(normed, 2012, 2, 15, 03, 53, 07, 0) - - def test_west_normalize(self): - str = '2012-02-14T20:53:07+21:00' - west = utils.parse_isotime(str) - normed = utils.normalize_time(west) - self._instaneous(normed, 2012, 2, 13, 23, 53, 07, 0) |
