Why timestamp + timezone rather than date stamp
John A Meinel
john at arbash-meinel.com
Thu Jun 30 20:18:00 BST 2005
John A Meinel wrote:
> I'm just wondering why Revision entries store the local timestamp
> (seconds since epoch) plus the local offset in seconds relative to GMT,
> rather than either storing a datestamp or a GMT timestamp, and then some
> information about what timezone it was committed in.
>
> If it was a resolution problem, the following code produces
> high-resolution datestamps:
>
> def format_highres_date(t, offset):
> import time
> tt = time.gmtime(t + offset)
> return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
> + ('%.9f' % (t - int(t)))[1:]
> + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
Just to add the other function, the following code unpacks the above
into the timestamp/timezone format. It isn't quite as pretty, but it
works. Comments and documentation and test code has been removed to keep
it simple:
def unpack_highres_date(date):
from bzrlib.osutils import local_time_offset
import time
dot_loc = date.find('.')
if dot_loc == -1:
raise ValueError('Date string does not contain high-precision
seconds: %r' % date)
base_time = time.strptime(date[:dot_loc], "%a %Y-%m-%d %H:%M:%S")
fract_seconds, offset = date[dot_loc:].split()
fract_seconds = float(fract_seconds)
offset = int(offset)
offset = int(offset / 100) * 3600 + offset % 100
# mktime returns the a local timestamp, not the timestamp based
# on the offset given in the file, so we need to adjust based
# on what the local offset is, and then re-adjust based on
# offset read
timestamp = time.mktime(base_time)
timestamp += local_time_offset(timestamp) - offset
# Add back in the fractional seconds
timestamp += fract_seconds
return (timestamp, offset)
My test code generates a random set of dates within 1 year of now, and
makes sure that converting into the datestamp and back into (timestamp,
timezone) is idempotent. And after a few thousand attempts, I haven't
found one that failed. It's a random test, not a systematic one, though.
I always thought that there would be some sort of rounding error, but
apparently "%.9f" is sufficient to prevent that.
Also, since there are 10 digits before the decimal, %.9f seems like it
is including quite a few bogus bits. Isn't there only 16 digits of
precision (or is that for single-precision floats).
Anyway, in my testing, the only way to get a stable '0' in the last
digit of precision was with:
print ('%.6f' % round(time.time(), 5))
So rounding to 5 places allows a format with 6 places to always put 0 in
the final place.
That gives us a precision of 10 microseconds, which I think is more than
enough.
So I guess I have 2 recommendations. First is to change to using a date
field instead of the mixed timestamp + timezone, and the second is to
switch to rounding the timestamp to 10 microseconds (but display all the
way down to microseconds). Actually I think we would be more than fine
to just save and display down to milliseconds
Both of these would mean updating your old revision XML, but we are
still in development, and that is what the "bzr upgrade" command is for.
For now, though, the changeset code will stick at 9 digits of precision,
since that is required for compatibility.
John
=:->
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 253 bytes
Desc: OpenPGP digital signature
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20050630/8212a967/attachment.pgp
More information about the bazaar
mailing list