Source code for genpy.rostime

# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following
#    disclaimer in the documentation and/or other materials provided
#    with the distribution.
#  * Neither the name of Willow Garage, Inc. nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

"""ROS Time representation, including Duration."""
from __future__ import division

import numbers


def _canon(secs, nsecs):
    # canonical form: nsecs is always positive, nsecs < 1 second
    secs_over = nsecs // 1000000000
    secs += secs_over
    nsecs -= secs_over * 1000000000
    return secs, nsecs


[docs]class TVal(object): """ Base class of :class:`Time` and :class:`Duration` representations. Representation is secs+nanoseconds since epoch. """ __slots__ = ['secs', 'nsecs'] # mimic same API as messages when being introspected _slot_types = ['int32', 'int32'] def __init__(self, secs=0, nsecs=0): # noqa: D205, D400 """ :param secs: seconds. If secs is a float, then nsecs must not be set or 0, larger seconds will be of type long on 32-bit systems, ``int/long/float`` :param nsecs: nanoseconds, ``int`` """ if not isinstance(secs, numbers.Integral): # float secs constructor if nsecs != 0: raise ValueError('if secs is a float, nsecs cannot be set') float_secs = secs secs = int(float_secs) nsecs = int((float_secs - secs) * 1000000000) else: secs = int(secs) nsecs = int(nsecs) self.secs, self.nsecs = _canon(secs, nsecs)
[docs] @classmethod def from_sec(cls, float_secs): """ Create new TVal instance using time.time() value (float seconds). :param float_secs: time value in time.time() format, ``float`` :returns: :class:`TVal` instance for specified time """ secs = int(float_secs) nsecs = int((float_secs - secs) * 1000000000) return cls(secs, nsecs)
[docs] def is_zero(self): # noqa: D200, D400, D401 """ :returns: ``True`` if time is zero (secs and nsecs are zero), ``bool`` """ return self.secs == 0 and self.nsecs == 0
[docs] def set(self, secs, nsecs): """ Set time using separate secs and nsecs values. :param secs: seconds since epoch, ``int`` :param nsecs: nanoseconds since seconds, ``int`` """ self.secs = secs self.nsecs = nsecs
[docs] def canon(self): """ Canonicalize the field representation in this instance. Should only be used when manually setting secs/nsecs slot values, as in deserialization. """ self.secs, self.nsecs = _canon(self.secs, self.nsecs)
[docs] def to_sec(self): # noqa: D200, D400, D401 """ :returns: time as float seconds (same as time.time() representation), ``float`` """ return float(self.secs) + float(self.nsecs) / 1e9
[docs] def to_nsec(self): # noqa: D200, D400, D401 """ :returns: time as nanoseconds, ``long`` """ return self.secs * int(1e9) + self.nsecs
def __hash__(self): """ Time values are hashable. Time values with identical fields have the same hash. """ return hash((self.secs, self.nsecs)) def __str__(self): return str(self.to_nsec()) def __repr__(self): return 'genpy.TVal[%d]' % self.to_nsec() def __nonzero__(self): """Return if time value is not zero.""" return self.secs != 0 or self.nsecs != 0 __bool__ = __nonzero__ def __lt__(self, other): """< test for time values.""" try: return self.__cmp__(other) < 0 except TypeError: return NotImplemented def __le__(self, other): """<= test for time values.""" try: return self.__cmp__(other) <= 0 except TypeError: return NotImplemented def __gt__(self, other): """> test for time values.""" try: return self.__cmp__(other) > 0 except TypeError: return NotImplemented def __ge__(self, other): """>= test for time values.""" try: return self.__cmp__(other) >= 0 except TypeError: return NotImplemented def __ne__(self, other): return not self.__eq__(other) def __cmp__(self, other): if not isinstance(other, TVal): raise TypeError('Cannot compare to non-TVal') a = self.to_nsec() b = other.to_nsec() return (a > b) - (a < b) def __eq__(self, other): if not isinstance(other, TVal): return False return self.to_nsec() == other.to_nsec()
[docs]class Time(TVal): """ Time contains the ROS-wide 'time' primitive representation. It consists of two integers: seconds since epoch and nanoseconds since seconds. Time instances are mutable. """ __slots__ = ['secs', 'nsecs'] def __init__(self, secs=0, nsecs=0): """ Construct time where secs and nsecs are integers. You may prefer to use the static L{from_sec()} factory method instead. :param secs: seconds since epoch, ``int`` :param nsecs: nanoseconds since seconds (since epoch), ``int`` """ super(Time, self).__init__(secs, nsecs) if self.secs < 0: raise TypeError('time values must be positive') def __getstate__(self): """Support for Python pickling.""" return [self.secs, self.nsecs] def __setstate__(self, state): """Support for Python pickling.""" self.secs, self.nsecs = state
[docs] def to_time(self): """ Get Time in time.time() format. alias of L{to_sec()}. :returns: time in floating point secs (time.time() format), ``float`` """ return self.to_sec()
def __hash__(self): return super(Time, self).__hash__() def __repr__(self): return 'genpy.Time[%d]' % self.to_nsec() def __add__(self, other): """ Add duration to this time. :param other: :class:`Duration` """ if not isinstance(other, Duration): return NotImplemented return self.__class__(self.secs + other.secs, self.nsecs + other.nsecs) __radd__ = __add__ def __sub__(self, other): """ Subtract time or duration from this time. :param other: :class:`Duration`/:class:`Time` :returns: :class:`Duration` if other is a :class:`Time`, :class:`Time` if other is a :class:`Duration` """ if isinstance(other, Time): return Duration(self.secs - other.secs, self.nsecs - other.nsecs) elif isinstance(other, Duration): return self.__class__(self.secs - other.secs, self.nsecs - other.nsecs) else: return NotImplemented def __cmp__(self, other): """ Compare to another time. :param other: :class:`Time` """ if not isinstance(other, Time): raise TypeError('cannot compare to non-Time') a = self.to_nsec() b = other.to_nsec() return (a > b) - (a < b) def __eq__(self, other): """ Equal test for Time. Comparison assumes that both time instances are in canonical representation; only compares fields. :param other: :class:`Time` """ if not isinstance(other, Time): return False return self.secs == other.secs and self.nsecs == other.nsecs
[docs]class Duration(TVal): """ Duration represents the ROS 'duration' primitive. It consists of two integers: seconds and nanoseconds. The Duration class allows you to add and subtract Duration instances, including adding and subtracting from :class:`Time` instances. """ __slots__ = ['secs', 'nsecs'] def __init__(self, secs=0, nsecs=0): """ Create new Duration instance. secs and nsecs are integers and correspond to the ROS 'duration' primitive. :param secs: seconds, ``int`` :param nsecs: nanoseconds, ``int`` """ super(Duration, self).__init__(secs, nsecs) def __getstate__(self): """Support for Python pickling.""" return [self.secs, self.nsecs] def __setstate__(self, state): """Support for Python pickling.""" self.secs, self.nsecs = state def __hash__(self): return super(Duration, self).__hash__() def __repr__(self): return 'genpy.Duration[%d]' % self.to_nsec() def __neg__(self): # noqa: D400, D401 """:returns: Negative value of this :class:`Duration`""" return self.__class__(-self.secs, -self.nsecs) def __abs__(self): """ Absolute value of this duration. :returns: positive :class:`Duration` """ if self.secs >= 0: return self return self.__neg__() def __add__(self, other): """ Add duration to this duration, or this duration to a time, creating a new time value as a result. :param other: duration or time, ``Duration``/``Time`` :returns: :class:`Duration` if other is a :class:`Duration` instance, :class:`Time` if other is a :class:`Time` """ if isinstance(other, Duration): return self.__class__(self.secs+other.secs, self.nsecs+other.nsecs) else: return NotImplemented __radd__ = __add__ def __sub__(self, other): """ Subtract duration from this duration, returning a new duration. :param other: duration :returns: :class:`Duration` """ if not isinstance(other, Duration): return NotImplemented return self.__class__(self.secs-other.secs, self.nsecs-other.nsecs) def __mul__(self, val): """ Multiply this duration by an integer or float. :param val: multiplication factor, ``int/float`` :returns: :class:`Duration` multiplied by val """ if isinstance(val, numbers.Integral): return self.__class__(self.secs * val, self.nsecs * val) elif isinstance(val, numbers.Real): return self.__class__.from_sec(self.to_sec() * val) else: return NotImplemented __rmul__ = __mul__ def __floordiv__(self, val): """ Floor divide this duration by an integer or float. :param val: division factor ``int/float``, or :class:`Duration` to divide by :returns: :class:`Duration` divided by val - a :class:`Duration` if divided by a number, or a number if divided by a duration """ if isinstance(val, numbers.Integral) or isinstance(val, numbers.Real): return self.__class__.from_sec(self.to_sec() // val) elif isinstance(val, Duration): return int(self.to_sec() // val.to_sec()) else: return NotImplemented def __div__(self, val): """ Divide this duration by an integer or float. :param val: division factor ``int/float``, or :class:`Duration` to divide by :returns: :class:`Duration` divided by val - a :class:`Duration` if divided by a number, or a number if divided by a duration """ if isinstance(val, numbers.Integral) or isinstance(val, numbers.Real): return self.__class__.from_sec(self.to_sec() / val) elif isinstance(val, Duration): return self.to_sec() / val.to_sec() else: return NotImplemented def __truediv__(self, val): """ Divide this duration by an integer or float. :param val: division factor ``int/float``, or :class:`Duration` to divide by :returns: :class:`Duration` divided by val - a :class:`Duration` if divided by a number, or a number if divided by a duration """ if isinstance(val, numbers.Real): return self.__class__.from_sec(self.to_sec() / val) elif isinstance(val, Duration): return self.to_sec() / val.to_sec() else: return NotImplemented def __mod__(self, val): """ Find the remainder when dividing this Duration by another Duration. :returns: :class:`Duration` The remaining time after the division """ if isinstance(val, Duration): return self.__class__.from_sec(self.to_sec() % val.to_sec()) else: return NotImplemented def __divmod__(self, val): """ Implement the builtin divmod for a pair of Durations. :returns: ``int`` The floored result of the division :returns: :class:`Duration` The remaining time after the division """ if isinstance(val, Duration): quotient, remainder = divmod(self.to_sec(), val.to_sec()) return int(quotient), self.__class__.from_sec(remainder) else: return NotImplemented def __cmp__(self, other): if not isinstance(other, Duration): raise TypeError('Cannot compare to non-Duration') a = self.to_nsec() b = other.to_nsec() return (a > b) - (a < b) def __eq__(self, other): if not isinstance(other, Duration): return False return self.secs == other.secs and self.nsecs == other.nsecs