timestamp.py
87 lines
| 2.5 KiB
| text/x-python
|
PythonLexer
Simon Sapin
|
r49079 | # Copyright Mercurial Contributors | ||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | ||||
Simon Sapin
|
r49081 | import functools | ||
Simon Sapin
|
r49079 | import stat | ||
rangemask = 0x7FFFFFFF | ||||
Simon Sapin
|
r49081 | @functools.total_ordering | ||
Simon Sapin
|
r49079 | class timestamp(tuple): | ||
""" | ||||
Simon Sapin
|
r49081 | A Unix timestamp with optional nanoseconds precision, | ||
Simon Sapin
|
r49079 | modulo 2**31 seconds. | ||
A 2-tuple containing: | ||||
`truncated_seconds`: seconds since the Unix epoch, | ||||
truncated to its lower 31 bits | ||||
`subsecond_nanoseconds`: number of nanoseconds since `truncated_seconds`. | ||||
Simon Sapin
|
r49081 | When this is zero, the sub-second precision is considered unknown. | ||
Simon Sapin
|
r49079 | """ | ||
def __new__(cls, value): | ||||
truncated_seconds, subsec_nanos = value | ||||
value = (truncated_seconds & rangemask, subsec_nanos) | ||||
return super(timestamp, cls).__new__(cls, value) | ||||
Simon Sapin
|
r49081 | def __eq__(self, other): | ||
self_secs, self_subsec_nanos = self | ||||
other_secs, other_subsec_nanos = other | ||||
return self_secs == other_secs and ( | ||||
self_subsec_nanos == other_subsec_nanos | ||||
or self_subsec_nanos == 0 | ||||
or other_subsec_nanos == 0 | ||||
) | ||||
def __gt__(self, other): | ||||
self_secs, self_subsec_nanos = self | ||||
other_secs, other_subsec_nanos = other | ||||
if self_secs > other_secs: | ||||
return True | ||||
if self_secs < other_secs: | ||||
return False | ||||
if self_subsec_nanos == 0 or other_subsec_nanos == 0: | ||||
# they are considered equal, so not "greater than" | ||||
return False | ||||
return self_subsec_nanos > other_subsec_nanos | ||||
Simon Sapin
|
r49079 | |||
def zero(): | ||||
""" | ||||
Returns the `timestamp` at the Unix epoch. | ||||
""" | ||||
return tuple.__new__(timestamp, (0, 0)) | ||||
def mtime_of(stat_result): | ||||
""" | ||||
Takes an `os.stat_result`-like object and returns a `timestamp` object | ||||
for its modification time. | ||||
""" | ||||
Simon Sapin
|
r49082 | try: | ||
# TODO: add this attribute to `osutil.stat` objects, | ||||
# see `mercurial/cext/osutil.c`. | ||||
# | ||||
# This attribute is also not available on Python 2. | ||||
nanos = stat_result.st_mtime_ns | ||||
except AttributeError: | ||||
# https://docs.python.org/2/library/os.html#os.stat_float_times | ||||
# "For compatibility with older Python versions, | ||||
# accessing stat_result as a tuple always returns integers." | ||||
secs = stat_result[stat.ST_MTIME] | ||||
Simon Sapin
|
r49079 | |||
Simon Sapin
|
r49082 | subsec_nanos = 0 | ||
else: | ||||
billion = int(1e9) | ||||
secs = nanos // billion | ||||
subsec_nanos = nanos % billion | ||||
Simon Sapin
|
r49079 | |||
return timestamp((secs, subsec_nanos)) | ||||