Spaces:
Runtime error
Runtime error
| # coding: utf-8 | |
| from collections import namedtuple | |
| import datetime | |
| import sys | |
| import struct | |
| PY2 = sys.version_info[0] == 2 | |
| if PY2: | |
| int_types = (int, long) | |
| _utc = None | |
| else: | |
| int_types = int | |
| try: | |
| _utc = datetime.timezone.utc | |
| except AttributeError: | |
| _utc = datetime.timezone(datetime.timedelta(0)) | |
| class ExtType(namedtuple("ExtType", "code data")): | |
| """ExtType represents ext type in msgpack.""" | |
| def __new__(cls, code, data): | |
| if not isinstance(code, int): | |
| raise TypeError("code must be int") | |
| if not isinstance(data, bytes): | |
| raise TypeError("data must be bytes") | |
| if not 0 <= code <= 127: | |
| raise ValueError("code must be 0~127") | |
| return super(ExtType, cls).__new__(cls, code, data) | |
| class Timestamp(object): | |
| """Timestamp represents the Timestamp extension type in msgpack. | |
| When built with Cython, msgpack uses C methods to pack and unpack `Timestamp`. When using pure-Python | |
| msgpack, :func:`to_bytes` and :func:`from_bytes` are used to pack and unpack `Timestamp`. | |
| This class is immutable: Do not override seconds and nanoseconds. | |
| """ | |
| __slots__ = ["seconds", "nanoseconds"] | |
| def __init__(self, seconds, nanoseconds=0): | |
| """Initialize a Timestamp object. | |
| :param int seconds: | |
| Number of seconds since the UNIX epoch (00:00:00 UTC Jan 1 1970, minus leap seconds). | |
| May be negative. | |
| :param int nanoseconds: | |
| Number of nanoseconds to add to `seconds` to get fractional time. | |
| Maximum is 999_999_999. Default is 0. | |
| Note: Negative times (before the UNIX epoch) are represented as negative seconds + positive ns. | |
| """ | |
| if not isinstance(seconds, int_types): | |
| raise TypeError("seconds must be an integer") | |
| if not isinstance(nanoseconds, int_types): | |
| raise TypeError("nanoseconds must be an integer") | |
| if not (0 <= nanoseconds < 10**9): | |
| raise ValueError( | |
| "nanoseconds must be a non-negative integer less than 999999999." | |
| ) | |
| self.seconds = seconds | |
| self.nanoseconds = nanoseconds | |
| def __repr__(self): | |
| """String representation of Timestamp.""" | |
| return "Timestamp(seconds={0}, nanoseconds={1})".format( | |
| self.seconds, self.nanoseconds | |
| ) | |
| def __eq__(self, other): | |
| """Check for equality with another Timestamp object""" | |
| if type(other) is self.__class__: | |
| return ( | |
| self.seconds == other.seconds and self.nanoseconds == other.nanoseconds | |
| ) | |
| return False | |
| def __ne__(self, other): | |
| """not-equals method (see :func:`__eq__()`)""" | |
| return not self.__eq__(other) | |
| def __hash__(self): | |
| return hash((self.seconds, self.nanoseconds)) | |
| def from_bytes(b): | |
| """Unpack bytes into a `Timestamp` object. | |
| Used for pure-Python msgpack unpacking. | |
| :param b: Payload from msgpack ext message with code -1 | |
| :type b: bytes | |
| :returns: Timestamp object unpacked from msgpack ext payload | |
| :rtype: Timestamp | |
| """ | |
| if len(b) == 4: | |
| seconds = struct.unpack("!L", b)[0] | |
| nanoseconds = 0 | |
| elif len(b) == 8: | |
| data64 = struct.unpack("!Q", b)[0] | |
| seconds = data64 & 0x00000003FFFFFFFF | |
| nanoseconds = data64 >> 34 | |
| elif len(b) == 12: | |
| nanoseconds, seconds = struct.unpack("!Iq", b) | |
| else: | |
| raise ValueError( | |
| "Timestamp type can only be created from 32, 64, or 96-bit byte objects" | |
| ) | |
| return Timestamp(seconds, nanoseconds) | |
| def to_bytes(self): | |
| """Pack this Timestamp object into bytes. | |
| Used for pure-Python msgpack packing. | |
| :returns data: Payload for EXT message with code -1 (timestamp type) | |
| :rtype: bytes | |
| """ | |
| if (self.seconds >> 34) == 0: # seconds is non-negative and fits in 34 bits | |
| data64 = self.nanoseconds << 34 | self.seconds | |
| if data64 & 0xFFFFFFFF00000000 == 0: | |
| # nanoseconds is zero and seconds < 2**32, so timestamp 32 | |
| data = struct.pack("!L", data64) | |
| else: | |
| # timestamp 64 | |
| data = struct.pack("!Q", data64) | |
| else: | |
| # timestamp 96 | |
| data = struct.pack("!Iq", self.nanoseconds, self.seconds) | |
| return data | |
| def from_unix(unix_sec): | |
| """Create a Timestamp from posix timestamp in seconds. | |
| :param unix_float: Posix timestamp in seconds. | |
| :type unix_float: int or float. | |
| """ | |
| seconds = int(unix_sec // 1) | |
| nanoseconds = int((unix_sec % 1) * 10**9) | |
| return Timestamp(seconds, nanoseconds) | |
| def to_unix(self): | |
| """Get the timestamp as a floating-point value. | |
| :returns: posix timestamp | |
| :rtype: float | |
| """ | |
| return self.seconds + self.nanoseconds / 1e9 | |
| def from_unix_nano(unix_ns): | |
| """Create a Timestamp from posix timestamp in nanoseconds. | |
| :param int unix_ns: Posix timestamp in nanoseconds. | |
| :rtype: Timestamp | |
| """ | |
| return Timestamp(*divmod(unix_ns, 10**9)) | |
| def to_unix_nano(self): | |
| """Get the timestamp as a unixtime in nanoseconds. | |
| :returns: posix timestamp in nanoseconds | |
| :rtype: int | |
| """ | |
| return self.seconds * 10**9 + self.nanoseconds | |
| def to_datetime(self): | |
| """Get the timestamp as a UTC datetime. | |
| Python 2 is not supported. | |
| :rtype: datetime. | |
| """ | |
| return datetime.datetime.fromtimestamp(0, _utc) + datetime.timedelta( | |
| seconds=self.to_unix() | |
| ) | |
| def from_datetime(dt): | |
| """Create a Timestamp from datetime with tzinfo. | |
| Python 2 is not supported. | |
| :rtype: Timestamp | |
| """ | |
| return Timestamp.from_unix(dt.timestamp()) | |