Timestamp: fix inconsistent raw and normal values

Previously it was possible for a Timestamp to have inconsistent raw
and normal values. For example:
>>> ts1 = Timestamp(1755077566.523385)
>>> (ts1.normal, ts1.raw, (~ts1).normal)
('1755077566.52339', 175507756652338, '8244922433.47661')
This results in the invert function not being reliably reversible:
(~(~ts1)).normal
'1755077566.52338'
The cause is that the normal value is based on Timestamp.timestamp
which preserves the precision of the value given to the constructor,
whereas the invert function uses the limited precision raw value.
This patch forces Timestamp.timestamp to have the limited precision
value of Timestamp.raw.
Change-Id: I4e7fd6078aae3f284628303f20ced66aa702c466
Signed-off-by: Alistair Coles <alistairncoles@gmail.com>
This commit is contained in:
Alistair Coles
2025年08月13日 13:18:39 +01:00
parent bdb052b59b
commit 93b88540dc

View File

@@ -89,7 +89,7 @@ class Timestamp(object):
timestamp = timestamp.decode('ascii')
if isinstance(timestamp, str):
base, base_offset = timestamp.partition('_')[::2]
self.timestamp = float(base)
float_timestamp = float(base)
if '_' in base_offset:
raise ValueError('invalid literal for int() with base 16: '
'%r' % base_offset)
@@ -98,7 +98,7 @@ class Timestamp(object):
else:
self.offset = 0
else:
self.timestamp = float(timestamp)
float_timestamp = float(timestamp)
self.offset = getattr(timestamp, 'offset', 0)
# increment offset
if offset >= 0:
@@ -107,14 +107,15 @@ class Timestamp(object):
raise ValueError('offset must be non-negative')
if self.offset > MAX_OFFSET:
raise ValueError('offset must be smaller than %d' % MAX_OFFSET)
self.raw = int(round(self.timestamp / PRECISION))
self.raw = int(round(float_timestamp / PRECISION))
# add delta
if delta:
self.raw = self.raw + delta
if self.raw <= 0:
raise ValueError(
'delta must be greater than %d' % (-1 * self.raw))
self.timestamp = float(self.raw * PRECISION)
self.timestamp = round(float(self.raw * PRECISION), 5)
if check_bounds:
if self.timestamp < 0:
raise ValueError('timestamp cannot be negative')

View File

@@ -121,14 +121,19 @@ class TestS3Timestamp(unittest.TestCase):
# integer
ts = utils.S3Timestamp(1)
self.assertEqual(expected, ts.s3xmlformat)
# microseconds digits are not included in Timestamp.normal so do not
# cause the timestamp to be rounded up
ts = utils.S3Timestamp(1.000001)
self.assertEqual(expected, ts.s3xmlformat)
# milliseconds unit should be rounded up
expected = '1970年01月01日T00:00:02.000Z'
ts = utils.S3Timestamp(1.1)
self.assertEqual(expected, ts.s3xmlformat)
# float (microseconds) should be floored too
ts = utils.S3Timestamp(1.000001)
# float (deca-microseconds) should be rounded up too
ts = utils.S3Timestamp(1.000010)
self.assertEqual(expected, ts.s3xmlformat)
# Bigger float (milliseconds) should be floored too
# Bigger float (milliseconds) should be rounded up too
ts = utils.S3Timestamp(1.9)
self.assertEqual(expected, ts.s3xmlformat)

View File

@@ -151,10 +151,13 @@ class TestTimestamp(unittest.TestCase):
def test_ceil(self):
self.assertEqual(0.0, timestamp.Timestamp(0).ceil())
self.assertEqual(1.0, timestamp.Timestamp(0.00001).ceil())
self.assertEqual(1.0, timestamp.Timestamp(0.000001).ceil())
self.assertEqual(0.0, timestamp.Timestamp(0.000001).ceil())
self.assertEqual(1.0, timestamp.Timestamp(0.000006).ceil())
self.assertEqual(12345678.0, timestamp.Timestamp(12345678.0).ceil())
self.assertEqual(12345679.0,
self.assertEqual(12345678.0,
timestamp.Timestamp(12345678.000001).ceil())
self.assertEqual(12345679.0,
timestamp.Timestamp(12345678.000006).ceil())
def test_not_equal(self):
ts = '1402436408.91203_0000000000000001'
@@ -311,11 +314,17 @@ class TestTimestamp(unittest.TestCase):
expected = 140243640891203
ts = timestamp.Timestamp(1402436408.91203)
self.assertEqual(expected, ts.raw)
self.assertEqual('1402436408.91203', ts.normal)
# 'raw' does not include offset
ts = timestamp.Timestamp(1402436408.91203, 0xf0)
self.assertEqual(expected, ts.raw)
expected = 175507756652338
ts = timestamp.Timestamp(1755077566.523385)
self.assertEqual(expected, ts.raw)
self.assertEqual('1755077566.52338', ts.normal)
def test_delta(self):
def _assertWithinBounds(expected, timestamp):
tolerance = 0.00001
@@ -780,6 +789,23 @@ class TestTimestamp(unittest.TestCase):
self.assertEqual(caught.exception.args[0],
'Cannot invert timestamps with offsets')
def test_inversion_reversibility(self):
ts = timestamp.Timestamp(1755077566.523385)
inv = ~ts
inv_inv = ~inv
self.assertEqual(ts, inv_inv)
self.assertEqual(ts.normal, inv_inv.normal)
inv_inv_inv = ~inv_inv
self.assertEqual(inv, inv_inv_inv)
self.assertEqual(inv.normal, inv_inv_inv.normal)
ts = timestamp.Timestamp.now()
inv = ~ts
inv_inv = ~inv
self.assertEqual(ts, inv_inv)
self.assertEqual(ts.normal, inv_inv.normal)
class TestTimestampEncoding(unittest.TestCase):
Reference in New Issue
openstack/swift
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.

The note is not visible to the blocked user.