|
6 | 6 | import tarantool.msgpack_ext.types.timezones as tt_timezones
|
7 | 7 | from tarantool.error import MsgpackError, MsgpackWarning, warn
|
8 | 8 |
|
| 9 | +from tarantool.msgpack_ext.types.interval import Interval, Adjust |
| 10 | + |
9 | 11 | # https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-datetime-type
|
10 | 12 | #
|
11 | 13 | # The datetime MessagePack representation looks like this:
|
|
45 | 47 | BYTEORDER = 'little'
|
46 | 48 |
|
47 | 49 | NSEC_IN_SEC = 1000000000
|
| 50 | +NSEC_IN_MKSEC = 1000 |
48 | 51 | SEC_IN_MIN = 60
|
49 | 52 | MIN_IN_DAY = 60 * 24
|
| 53 | +MONTH_IN_YEAR = 12 |
50 | 54 |
|
51 | 55 |
|
52 | 56 | def get_bytes_as_int(data, cursor, size):
|
@@ -209,6 +213,58 @@ def __init__(self, *args, tarantool_tzindex=None, **kwargs):
|
209 | 213 | self._tzoffset = tzoffset
|
210 | 214 | self._tzindex = tzindex
|
211 | 215 |
|
| 216 | + def __add__(self, other): |
| 217 | + if not isinstance(other, Interval): |
| 218 | + raise TypeError(f"unsupported operand type(s) for -: '{type(self)}' and '{type(other)}'") |
| 219 | + |
| 220 | + self_ts = self._timestamp |
| 221 | + |
| 222 | + # https://github.com/tarantool/tarantool/wiki/Datetime-Internals#date-adjustions-and-leap-years |
| 223 | + months = other.year * MONTH_IN_YEAR + other.month |
| 224 | + |
| 225 | + res = self_ts + pandas.DateOffset(months = months) |
| 226 | + |
| 227 | + # pandas.DateOffset works like Adjust.Limit |
| 228 | + if other.adjust == Adjust.Excess: |
| 229 | + if self_ts.day > res.day: |
| 230 | + res = res + pandas.DateOffset(days = self_ts.day - res.day) |
| 231 | + elif other.adjust == Adjust.Last: |
| 232 | + if self_ts.is_month_end: |
| 233 | + # day replaces days |
| 234 | + res = res.replace(day = res.days_in_month) |
| 235 | + |
| 236 | + res = res + pandas.Timedelta(weeks = other.week, |
| 237 | + days = other.day, |
| 238 | + hours = other.hour, |
| 239 | + minutes = other.minute, |
| 240 | + seconds = other.second, |
| 241 | + nanoseconds = other.nanosecond) |
| 242 | + |
| 243 | + if self._tzindex != 0: |
| 244 | + return Datetime(res, tarantool_tzindex=self._tzindex) |
| 245 | + else: |
| 246 | + return Datetime(res) |
| 247 | + |
| 248 | + def __sub__(self, other): |
| 249 | + if not isinstance(other, Datetime): |
| 250 | + raise TypeError(f"unsupported operand type(s) for -: '{type(self)}' and '{type(other)}'") |
| 251 | + |
| 252 | + self_ts = self._timestamp |
| 253 | + other_ts = other._timestamp |
| 254 | + |
| 255 | + self_nsec = self_ts.microsecond * NSEC_IN_MKSEC + self_ts.nanosecond |
| 256 | + other_nsec = other_ts.microsecond * NSEC_IN_MKSEC + other_ts.nanosecond |
| 257 | + |
| 258 | + return Interval( |
| 259 | + year = self_ts.year - other_ts.year, |
| 260 | + month = self_ts.month - other_ts.month, |
| 261 | + day = self_ts.day - other_ts.day, |
| 262 | + hour = self_ts.hour - other_ts.hour, |
| 263 | + minute = self_ts.minute - other_ts.minute, |
| 264 | + second = self_ts.second - other_ts.second, |
| 265 | + nanosecond = self_nsec - other_nsec, |
| 266 | + ) |
| 267 | + |
212 | 268 | def __eq__(self, other):
|
213 | 269 | if isinstance(other, Datetime):
|
214 | 270 | return self._timestamp == other._timestamp
|
|
0 commit comments