Merge "Support non-UTC timestamps in changes-since filter"
This commit is contained in:
@@ -1528,7 +1528,7 @@ def instance_get_all_by_filters(context, filters):
|
|||||||
filters = filters.copy()
|
filters = filters.copy()
|
||||||
|
|
||||||
if 'changes-since' in filters:
|
if 'changes-since' in filters:
|
||||||
changes_since = filters['changes-since']
|
changes_since = utils.normalize_time(filters['changes-since'])
|
||||||
query_prefix = query_prefix.\
|
query_prefix = query_prefix.\
|
||||||
filter(models.Instance.updated_at > changes_since)
|
filter(models.Instance.updated_at > changes_since)
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ import json
|
|||||||
import urlparse
|
import urlparse
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
import iso8601
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
@@ -889,7 +890,8 @@ class ServersControllerTest(test.TestCase):
|
|||||||
def fake_get_all(compute_self, context, search_opts=None):
|
def fake_get_all(compute_self, context, search_opts=None):
|
||||||
self.assertNotEqual(search_opts, None)
|
self.assertNotEqual(search_opts, None)
|
||||||
self.assertTrue('changes-since' in search_opts)
|
self.assertTrue('changes-since' in search_opts)
|
||||||
changes_since = datetime.datetime(2011, 1, 24, 17, 8, 1)
|
changes_since = datetime.datetime(2011, 1, 24, 17, 8, 1,
|
||||||
|
tzinfo=iso8601.iso8601.UTC)
|
||||||
self.assertEqual(search_opts['changes-since'], changes_since)
|
self.assertEqual(search_opts['changes-since'], changes_since)
|
||||||
self.assertTrue('deleted' not in search_opts)
|
self.assertTrue('deleted' not in search_opts)
|
||||||
return [fakes.stub_instance(100, uuid=server_uuid)]
|
return [fakes.stub_instance(100, uuid=server_uuid)]
|
||||||
|
@@ -15,13 +15,15 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import __builtin__
|
import __builtin__
|
||||||
import mox
|
|
||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import StringIO
|
import StringIO
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
import iso8601
|
||||||
|
import mox
|
||||||
|
|
||||||
import nova
|
import nova
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
@@ -700,3 +702,108 @@ class DeprecationTest(test.TestCase):
|
|||||||
h1 = utils.hash_file(flo)
|
h1 = utils.hash_file(flo)
|
||||||
h2 = hashlib.sha1(data).hexdigest()
|
h2 = hashlib.sha1(data).hexdigest()
|
||||||
self.assertEquals(h1, h2)
|
self.assertEquals(h1, h2)
|
||||||
|
|
||||||
|
|
||||||
|
class Iso8601TimeTest(test.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)
|
||||||
|
@@ -44,6 +44,7 @@ from eventlet import event
|
|||||||
from eventlet import greenthread
|
from eventlet import greenthread
|
||||||
from eventlet import semaphore
|
from eventlet import semaphore
|
||||||
from eventlet.green import subprocess
|
from eventlet.green import subprocess
|
||||||
|
import iso8601
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from nova import exception
|
from nova import exception
|
||||||
@@ -53,7 +54,7 @@ from nova.openstack.common import cfg
|
|||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
ISO_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
ISO_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
|
||||||
PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
|
PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
@@ -534,13 +535,27 @@ def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT):
|
|||||||
|
|
||||||
|
|
||||||
def isotime(at=None):
|
def isotime(at=None):
|
||||||
"""Returns iso formatted utcnow."""
|
"""Stringify time in ISO 8601 format"""
|
||||||
return strtime(at, ISO_TIME_FORMAT)
|
if not at:
|
||||||
|
at = datetime.datetime.utcnow()
|
||||||
|
str = at.strftime(ISO_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):
|
def parse_isotime(timestr):
|
||||||
"""Turn an iso formatted time back into a datetime."""
|
"""Turn an iso formatted time back into a datetime."""
|
||||||
return parse_strtime(timestr, ISO_TIME_FORMAT)
|
try:
|
||||||
|
return iso8601.parse_date(timestr)
|
||||||
|
except (iso8601.ParseError, 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 parse_mailmap(mailmap='.mailmap'):
|
def parse_mailmap(mailmap='.mailmap'):
|
||||||
|
@@ -33,3 +33,4 @@ paramiko
|
|||||||
feedparser
|
feedparser
|
||||||
pycrypto
|
pycrypto
|
||||||
Babel>=0.9.6
|
Babel>=0.9.6
|
||||||
|
iso8601>=0.1.4
|
||||||
|
Reference in New Issue
Block a user