python.observation.timeslot
Created on Sun Jan 2 18:30:14 2022
@author: Philippe@loco-labs.io
The python.observation.timeslot
module contains the TimeSlot
and the TimeInterval
classes.
What is the TimeSlot Object ?
The TimeSlot Object is a representation of time intervals data and properties. For example, I can represent the working day of 2022-march-15 by a TimeSlot which includes the following intervals:
- from 9 a.m. to 12 p.m.
- from 2 p.m. to 4:30 p.m.
- from 5 p.m. to 7:30 p.m. i.e. a duration of 8 hours centered around 3 p.m. with bounds at 9 a.m. and 7:30 p.m.
Main principles
The main principles are as follows :
Data structure
A TimeSlot
is a list of TimeInterval
.
A TimeInterval
is defined by two datetime
objects (start and end)
Multiple properties are associated with the data :
- duration : sum of the lenght of each TimeInterval
- centroïd : instant assicited to the middle of the duration
- bounds : minimum, maximum and middle
- type : instant, interval or slot
Relationships and assembly
Two TimeSlot
can be compared with five statuses (equals, contains, within, disjoint, intersects).
Multiple operations between two objects can be performed :
1# -*- coding: utf-8 -*- 2""" 3Created on Sun Jan 2 18:30:14 2022 4 5@author: Philippe@loco-labs.io 6 7The `python.observation.timeslot` module contains the `TimeSlot` and the `TimeInterval` classes. 8 9# What is the TimeSlot Object ? 10 11The TimeSlot Object is a representation of time intervals data and properties. For example, 12 I can represent the working day of 2022-march-15 by a TimeSlot which includes the following intervals: 13- from 9 a.m. to 12 p.m. 14- from 2 p.m. to 4:30 p.m. 15- from 5 p.m. to 7:30 p.m. 16i.e. a duration of 8 hours centered around 3 p.m. with bounds at 9 a.m. and 7:30 p.m. 17 18# Main principles 19 20The main principles are as follows : 21 22<img src="./timeslot_data_structure.png" width="800"> 23 24## Data structure 25 26A `TimeSlot` is a list of `TimeInterval`. 27 28A `TimeInterval` is defined by two `datetime` objects (start and end) 29 30Multiple properties are associated with the data : 31 32- duration : sum of the lenght of each TimeInterval 33- centroïd : instant assicited to the middle of the duration 34- bounds : minimum, maximum and middle 35- type : instant, interval or slot 36 37## Relationships and assembly 38 39Two `TimeSlot` can be compared with five statuses (equals, contains, within, disjoint, intersects). 40 41Multiple operations between two objects can be performed : 42 43- union between two `TimeSlot` 44- intersection between two `TimeSlot` 45- complementing a `TimeSlot` in an interval 46 47""" 48import datetime 49import json 50import numpy 51import pandas 52import bson 53 54from observation.esconstante import ES # , _identity 55 56 57class TimeSlotEncoder(json.JSONEncoder): 58 """add a new json encoder for TimeSlot""" 59 60 def default(self, o): 61 if isinstance(o, datetime.datetime): 62 return o.isoformat() 63 return json.JSONEncoder.default(self, o) 64 65 66class TimeSlot: 67 ''' 68 *Attributes (for @property see methods)* : 69 70 - **slot** : list of `TimeInterval` 71 72 The methods defined in this class are : 73 74 *dynamic value property (getters)* 75 76 - `TimeSlot.Bounds` 77 - `TimeSlot.bounds` 78 - `TimeSlot.Centroid` 79 - `TimeSlot.duration` 80 - `TimeSlot.instant` 81 - `TimeSlot.middle` 82 - `TimeSlot.interval` 83 - `TimeSlot.stype` 84 85 *instance methods* 86 87 - `TimeSlot.json` 88 - `TimeSlot.link` 89 - `TimeSlot.timetuple` 90 - `TimeSlot.union` 91 ''' 92 93 def __init__(self, val=None): 94 ''' 95 TimeSlot constructor. 96 97 *Parameters* 98 99 - **val** : date, interval, list of interval (default None) - with several formats 100 (tuple, list, string, datetime, TimeSlot, TimeInterval, numpy datetime64, pandas timestamp) 101 102 *Returns* : None''' 103 slot = [] 104 if isinstance(val, str): 105 try: 106 val = json.loads(val) 107 except: 108 val = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 109 # try: val = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 110 # except: val = None 111 if val == None: 112 self.slot = slot 113 return 114 val = TimeSlot._listed(val) 115 #if isinstance(val, tuple): val = list(val) 116 if isinstance(val, list) and len(val) == 2 and not isinstance(val[0], TimeInterval): 117 try: 118 slot.append(TimeInterval(val)) 119 except: 120 for interv in val: 121 slot.append(TimeInterval(interv)) 122 elif isinstance(val, list): 123 try: 124 for interv in val: 125 slot.append(TimeInterval(interv)) 126 except: 127 slot.append(TimeInterval(val)) 128 elif isinstance(val, datetime.datetime): 129 slot.append(TimeInterval(val)) 130 elif isinstance(val, TimeSlot): 131 slot = val.slot 132 elif isinstance(val, TimeInterval): 133 slot.append(val) 134 else: 135 slot.append(TimeInterval(val)) 136 self.slot = TimeSlot._reduced(slot) 137 138 def __add__(self, other): 139 ''' Add other's values to self's values in a new TimeSlot''' 140 return TimeSlot(TimeSlot._reduced(self.slot + other.slot)) 141 142 def __iadd__(self, other): 143 ''' Add other's values to self's values''' 144 self.slot = self._reduced(self.slot + other.slot) 145 146 def __contains__(self, item): 147 ''' item of extval''' 148 return item in self.slot 149 150 def __getitem__(self, index): 151 ''' return interval item''' 152 return self.slot[index] 153 154 def __setitem__(self, index, interv): 155 ''' modify interval item''' 156 if index < 0 or index >= len(self): 157 raise TimeSlotError("out of bounds") 158 self.slot[index] = TimeInterval(interv) 159 self.slot = TimeSlot._reduced(self.slot) 160 161 def __len__(self): 162 '''return the number of intervals included''' 163 return len(self.slot) 164 165 # def __repr__(self): 166 def __str__(self): 167 ''' return the type of slot and the json representation''' 168 return self.stype + '\n' + self.json(encoded=True, encode_format='json') 169 170 def __repr__(self): 171 # return self.__class__.__name__ + f'({self.slot})' 172 return self.__class__.__name__ + '(' + self.json(encoded=True, encode_format='json') + ')' 173 174 def __eq__(self, other): 175 '''equal if the slots are equals''' 176 try: 177 return self.slot == other.slot 178 except: 179 return False 180 181 def __lt__(self, other): 182 '''compare the earliest dates''' 183 return self.slot[0] < other.slot[0] 184 185 def __hash__(self): 186 return sum(hash(interv) for interv in self.slot) 187 # return hash(self.json(True)) 188 189 @property 190 def Bounds(self): 191 '''return an interval TimeSlot with the bounds of the TimeSlot object''' 192 return TimeSlot(self.bounds) 193 194 @property 195 def bounds(self): 196 '''return a tuple with the start and end dates with isoformat string''' 197 return (TimeSlot.form(self.slot[0].start), TimeSlot.form(self.slot[len(self) - 1].end)) 198 199 @classmethod 200 def cast(cls, value): 201 ''' 202 tranform a value (unique or list) in a list of `TimeSlot` 203 204 *Parameters* 205 206 - **value** : value to transform 207 208 *Returns* 209 210 - **list** : list of `TimeSlot` 211 ''' 212 if isinstance(value, list): 213 try: 214 return [cls(val) for val in value] 215 except: 216 return [cls(value)] 217 else: 218 return [cls(value)] 219 220 @property 221 def Centroid(self): 222 '''return a TimeSlot with the date corresponding to the middle of the duration''' 223 return TimeSlot(self.instant) 224 225 @property 226 def duration(self): 227 '''cumulative duration of each interval (timedelta format)''' 228 duration = datetime.timedelta() 229 for interv in self.slot: 230 duration += interv.duration 231 return duration 232 233 @staticmethod 234 def form(dtime): 235 if dtime.timetuple()[3:6] == (0, 0, 0): 236 return dtime.date().isoformat() 237 return dtime.isoformat() 238 239 @property 240 def instant(self): 241 '''return the date corresponding to the middle of the duration (datetime format)''' 242 duration = self.duration / 2 243 for interv in self.slot: 244 if duration > interv.duration: 245 duration -= interv.duration 246 else: 247 return interv.start + duration 248 249 @property 250 def middle(self): 251 '''return the date corresponding to the middle of the bounds (datetime format)''' 252 return self.bounds.instant 253 254 @property 255 def name(self): 256 ''' class name''' 257 return self.__class__.__name__ 258 259 @property 260 def interval(self): 261 '''return a list with the start and end dates (datetime format)''' 262 return [self.slot[0].start, self.slot[len(self) - 1].end] 263 264 @property 265 def stype(self): 266 '''return a string with the type of TimeSlot (instant, interval, slot)''' 267 if len(self.slot) == 1: 268 return self.slot[0].stype 269 else: 270 return 'slot' 271 272 def json(self, **kwargs): 273 ''' 274 Return json/bson structure with the list of TimeInterval. 275 276 *Parameters* 277 278 - **encoded** : defaut False - if False return dict, else return json string/bson bytes 279 - **encode_format** : defaut 'json' - return json, bson or cbor format 280 281 *Returns* : string or dict''' 282 option = {'encoded': False, 'encode_format': 'json'} | kwargs 283 if len(self) == 1: 284 js = self.slot[0].json( 285 encoded=False, encode_format=option['encode_format']) 286 else: 287 js = [interv.json( 288 encoded=False, encode_format=option['encode_format']) for interv in self.slot] 289 if option['encoded'] and option['encode_format'] == 'json': 290 return json.dumps(js, cls=TimeSlotEncoder) 291 if option['encoded'] and option['encode_format'] == 'bson': 292 return bson.encode(js) 293 return js 294 295 def link(self, other): 296 ''' 297 Return the status (string) of the link between two TimeSlot (self and other). 298 - equals : if self and other are the same 299 - disjoint : if self's intervals and other's intervals are all disjoint 300 - within : if all self's intervals are included in other's intervals 301 - contains : if all other's intervals are included in self's intervals 302 - intersects : in the others cases 303 304 *Parameters* 305 306 - **other** : TimeSlot to be compared 307 308 *Returns* 309 310 - **tuple** : (string(status), boolean(full or not))''' 311 if self.stype == 'instant': 312 point, oslot = self[0], other 313 elif other.stype == 'instant': 314 point, oslot = other[0], self 315 else: 316 point = None 317 if point is not None: 318 contains = equals = False 319 for interv in oslot: 320 contains = contains or interv.link(point) == 'contains' 321 equals = equals or interv.link(point) == 'equals' 322 if equals and not contains: 323 return ('equals', True) 324 if contains and point == other[0]: 325 return ('contains', True) 326 if contains and point == self[0]: 327 return ('within', True) 328 return ('disjoint', True) 329 else: 330 union = self + other 331 link = 'intersects' 332 full = True 333 if union.duration == self.duration == other.duration: 334 full = len(union) == len(self) == len(other) 335 link = 'equals' 336 elif union.duration == self.duration: 337 full = len(union) == len(self) 338 link = 'contains' 339 elif union.duration == other.duration: 340 full = len(union) == len(other) 341 link = 'within' 342 elif union.duration == self.duration + other.duration: 343 full = len(union) == len(self) + len(other) 344 link = 'disjoint' 345 return (link, full) 346 347 def timetuple(self, index=0, encoded=False): 348 ''' 349 Return json structure with the list of TimeInterval (timetuple filter). 350 351 *Parameters* 352 353 - **index** : integer, defaut 0 - timetuple format to apply : 354 - 0 : year 355 - 1 : month 356 - 2 : day 357 - 3 : hour 358 - 4 : minute 359 - 5 : seconds 360 - 6 : weekday 361 - 7 : yearday 362 - 8 : isdst (1 when daylight savings time is in effect, 0 when is not) 363 - **encoded** : defaut False - if True return string, else return dict 364 365 *Returns* : string or dict''' 366 if len(self) == 1: 367 js = self.slot[0].timetuple(index, False) 368 else: 369 js = [interv.timetuple(index, False) for interv in self.slot] 370 if encoded: 371 return json.dumps(js, cls=TimeSlotEncoder) 372 else: 373 return js 374 375 def union(self, other): 376 ''' Add other's values to self's values in a new TimeSlot (same as __add__)''' 377 return self.__add__(other) 378 379 @staticmethod 380 def _reduced(listinterv): 381 ''' return an ordered and non-overlapping list of TimeInterval from any TimeInterval list''' 382 if not isinstance(listinterv, list) or len(listinterv) == 0: 383 return [] 384 union = [] 385 slot = sorted(listinterv) 386 interv = slot[0] 387 i = j = 0 388 while i < len(slot): 389 for j in range(i + 1, len(slot)): 390 if interv.link(slot[j]) == 'within': 391 interv = slot[j] 392 elif interv.link(slot[j]) == 'intersects': 393 interv = interv.union(slot[j]) 394 elif interv.link(slot[j]) == 'disjoint': 395 union.append(interv) 396 interv = slot[j] 397 i = j 398 break 399 if j >= len(slot) - 1: 400 union.append(interv) 401 break 402 return union 403 404 @staticmethod 405 def _listed(idx): 406 '''transform a tuple of tuple in a list of list''' 407 if not isinstance(idx, str) and hasattr(idx, '__iter__'): 408 return [val if not isinstance(val, tuple) else TimeSlot._listed(val) for val in idx] 409 return idx 410 411 412class TimeInterval: # !!! interval 413 ''' 414 *Attributes (for @property see methods)* : 415 416 - **start** : datetime Object - start of `TimeInterval` 417 - **end** : datetime Object - end of `TimeInterval` 418 419 The methods defined in this class are : 420 421 *dynamic value property (getters)* 422 423 - `TimeInterval.Bounds` 424 - `TimeInterval.bounds` 425 - `TimeInterval.Centroid` 426 - `TimeInterval.duration` 427 - `TimeInterval.instant` 428 - `TimeInterval.stype` 429 430 *instance methods* 431 432 - `TimeInterval.json` 433 - `TimeInterval.link` 434 - `TimeInterval.timetuple` 435 - `TimeInterval.union` 436 ''' 437 438 def __init__(self, val=ES.nullDate): 439 ''' 440 TimeInterval constructor. 441 442 *Parameters* 443 444 - **val** : date, interval (default ES.nullDate) - with several formats 445 (list, string, datetime, TimeInterval, numpy datetime64, pandas timestamp) 446 447 *Returns* : None''' 448 self.start = self.end = ES.nullDate 449 if isinstance(val, str): 450 try: 451 sl = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 452 if sl != None: 453 self.start = self.end = sl 454 return 455 except: 456 try: 457 val = json.loads(val) 458 except: 459 val = ES.nullDate 460 if isinstance(val, list): 461 self._initInterval(val) 462 elif isinstance(val, TimeInterval): 463 self.start, self.end = val.start, val.end 464 else: 465 dat = self._initDat(val) 466 if dat != None: 467 self.start = self.end = dat 468 469 # def __repr__(self): 470 def __str__(self): 471 ''' return the type of interval and the json representation''' 472 return self.stype + '\n' + self.json(encoded=True, encode_format='json') 473 474 def __repr__(self): 475 # if self.stype == 'instant' : return self.__class__.__name__ + f'("{self.start}")' 476 # return self.__class__.__name__ + f'(["{self.start}","{self.end}"])' 477 return self.__class__.__name__ + '(' + self.json(encoded=True, encode_format='json') + ')' 478 479 def __eq__(self, other): 480 '''equal if the 'start' and 'end' dates are equals''' 481 return self.start == other.start and self.end == other.end 482 483 def __lt__(self, other): 484 '''compare the earliest dates (start)''' 485 return self.start < other.start 486 487 def __hash__(self): 488 return hash(self.start) + hash(self.end) 489 # return hash(self.json(True)) 490 491 @property 492 def bounds(self): 493 '''return a tuple with the start and end dates with isoformat string''' 494 return (TimeSlot.form(self.start), TimeSlot.form(self.end)) 495 496 @property 497 def Centroid(self): 498 '''return a TimeInterval with the date corresponding to the middle of the interval''' 499 return TimeInterval(self.instant) 500 501 @property 502 def duration(self): 503 '''duration between 'end' and 'start' date (timedelta format)''' 504 return self.end - self.start 505 506 @property 507 def instant(self): 508 '''return the date corresponding to the middle of the duration (datetime format)''' 509 return self.start + (self.end - self.start) / 2 510 511 @property 512 def stype(self): 513 '''return a string with the type of TimeInterval (instant, interval)''' 514 if self.start == self.end: 515 return 'instant' 516 return 'interval' 517 518 def json(self, encoded=False, encode_format='json'): 519 ''' 520 Return json/bson structure (date if 'instant' or [start, end] if 'interval') 521 with datetime or datetime.isoformat for dates. 522 523 *Parameters* 524 525 - **encoded** : defaut False - if True return dict, else return json string/bson bytes 526 - **encode_format** : defaut 'json' - return json, bson or cbor format 527 528 *Returns* : string or dict''' 529 if self.stype == 'instant': 530 js = self.start 531 else: 532 js = [self.start, self.end] 533 '''if self.stype == 'instant' : 534 if encode_format == 'bson': js = self.start 535 else: 536 js = TimeSlot.form(self.start) 537 elif self.stype == 'interval' : 538 if encode_format == 'bson': js = [self.start, self.end] 539 else: js = [TimeSlot.form(self.start), TimeSlot.form(self.end)]''' 540 if encoded and encode_format == 'json': 541 return json.dumps(js, cls=TimeSlotEncoder) 542 if encoded and encode_format == 'bson': 543 return bson.encode(js) 544 return js 545 546 def link(self, other): 547 ''' 548 Return the status (string) of the link between two TimeIntervals (self and other). 549 - equals : if self and other are the same 550 - disjoint : if self's interval and other's interval are disjoint 551 - within : if other's interval is included in self's interval 552 - contains : if self's interval is included in other's interval 553 - intersects : in the others cases 554 555 *Parameters* 556 557 - **other** : TimeInterval to be compared 558 559 *Returns* : string''' 560 if self.start == other.start and self.end == other.end: 561 return 'equals' 562 if self.start <= other.start and self.end >= other.end: 563 return 'contains' 564 if self.start >= other.start and self.end <= other.end: 565 return 'within' 566 if self.start <= other.end and self.end >= other.start: 567 return 'intersects' 568 return 'disjoint' 569 570 def timetuple(self, index=0, encoded=False): 571 ''' 572 Return json structure (timetuple filter). 573 574 *Parameters* 575 576 - **index** : integer, defaut 0 - timetuple format to apply : 577 - 0 : year 578 - 1 : month 579 - 2 : day 580 - 3 : hour 581 - 4 : minute 582 - 5 : seconds 583 - 6 : weekday 584 - 7 : yearday 585 - 8 : isdst (1 when daylight savings time is in effect, 0 when is not) 586 - **encoded** : defaut False - if True return string, else return dict 587 588 *Returns* : string or dict''' 589 if index not in [0, 1, 2, 3, 4, 5, 6, 7, 8]: 590 return None 591 if self.stype == 'instant': 592 js = self.start.timetuple()[index] 593 elif self.stype == 'interval': 594 js = [self.start.timetuple()[index], self.end.timetuple()[index]] 595 if encoded: 596 return json.dumps(js, cls=TimeSlotEncoder) 597 else: 598 return js 599 600 def union(self, other): 601 ''' Add other's values to self's values in a new TimeInterval 602 if self and other are not disjoint''' 603 if self.link(other) != 'disjoint': 604 return TimeInterval([min(self.start, other.start), max(self.end, other.end)]) 605 else: 606 return None 607 608 def _initInterval(self, val): 609 '''initialization of start and end dates from a list''' 610 self.start = self.end = self._initDat(val[0]) 611 if len(val) > 1: 612 self.end = self._initDat(val[1]) 613 else: 614 self.start = self.end = self._initDat(val) 615 if self.end < self.start: 616 self.start, self.end = self.end, self.start 617 618 def _initDat(self, val): 619 '''initialization of start and end dates from a unique value 620 (datetime, string, numpy.datetime64, pandas Timestamp)''' 621 if isinstance(val, datetime.datetime): 622 res = val 623 '''if val.tzinfo is None or val.tzinfo.utcoffset(val) is None: 624 res = val.astimezone(datetime.timezone.utc) 625 else: res = val''' 626 elif isinstance(val, str): 627 try: 628 res = datetime.datetime.fromisoformat(val) 629 except: 630 res = ES.nullDate 631 elif isinstance(val, numpy.datetime64): 632 res = pandas.Timestamp(val).to_pydatetime() 633 elif isinstance(val, pandas._libs.tslibs.timestamps.Timestamp): 634 res = val.to_pydatetime() 635 else: 636 raise TimeSlotError("impossible to convert in a date") 637 return TimeInterval._dattz(res) 638 639 @staticmethod 640 def _dattz(val): 641 if val.tzinfo is None or val.tzinfo.utcoffset(val) is None: 642 return val.replace(tzinfo=datetime.timezone.utc) 643 return val 644 645 646class TimeSlotError(Exception): 647 pass
58class TimeSlotEncoder(json.JSONEncoder): 59 """add a new json encoder for TimeSlot""" 60 61 def default(self, o): 62 if isinstance(o, datetime.datetime): 63 return o.isoformat() 64 return json.JSONEncoder.default(self, o)
add a new json encoder for TimeSlot
61 def default(self, o): 62 if isinstance(o, datetime.datetime): 63 return o.isoformat() 64 return json.JSONEncoder.default(self, o)
Implement this method in a subclass such that it returns
a serializable object for o
, or calls the base implementation
(to raise a TypeError
).
For example, to support arbitrary iterators, you could implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
Inherited Members
- json.encoder.JSONEncoder
- JSONEncoder
- item_separator
- key_separator
- skipkeys
- ensure_ascii
- check_circular
- allow_nan
- sort_keys
- indent
- encode
- iterencode
67class TimeSlot: 68 ''' 69 *Attributes (for @property see methods)* : 70 71 - **slot** : list of `TimeInterval` 72 73 The methods defined in this class are : 74 75 *dynamic value property (getters)* 76 77 - `TimeSlot.Bounds` 78 - `TimeSlot.bounds` 79 - `TimeSlot.Centroid` 80 - `TimeSlot.duration` 81 - `TimeSlot.instant` 82 - `TimeSlot.middle` 83 - `TimeSlot.interval` 84 - `TimeSlot.stype` 85 86 *instance methods* 87 88 - `TimeSlot.json` 89 - `TimeSlot.link` 90 - `TimeSlot.timetuple` 91 - `TimeSlot.union` 92 ''' 93 94 def __init__(self, val=None): 95 ''' 96 TimeSlot constructor. 97 98 *Parameters* 99 100 - **val** : date, interval, list of interval (default None) - with several formats 101 (tuple, list, string, datetime, TimeSlot, TimeInterval, numpy datetime64, pandas timestamp) 102 103 *Returns* : None''' 104 slot = [] 105 if isinstance(val, str): 106 try: 107 val = json.loads(val) 108 except: 109 val = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 110 # try: val = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 111 # except: val = None 112 if val == None: 113 self.slot = slot 114 return 115 val = TimeSlot._listed(val) 116 #if isinstance(val, tuple): val = list(val) 117 if isinstance(val, list) and len(val) == 2 and not isinstance(val[0], TimeInterval): 118 try: 119 slot.append(TimeInterval(val)) 120 except: 121 for interv in val: 122 slot.append(TimeInterval(interv)) 123 elif isinstance(val, list): 124 try: 125 for interv in val: 126 slot.append(TimeInterval(interv)) 127 except: 128 slot.append(TimeInterval(val)) 129 elif isinstance(val, datetime.datetime): 130 slot.append(TimeInterval(val)) 131 elif isinstance(val, TimeSlot): 132 slot = val.slot 133 elif isinstance(val, TimeInterval): 134 slot.append(val) 135 else: 136 slot.append(TimeInterval(val)) 137 self.slot = TimeSlot._reduced(slot) 138 139 def __add__(self, other): 140 ''' Add other's values to self's values in a new TimeSlot''' 141 return TimeSlot(TimeSlot._reduced(self.slot + other.slot)) 142 143 def __iadd__(self, other): 144 ''' Add other's values to self's values''' 145 self.slot = self._reduced(self.slot + other.slot) 146 147 def __contains__(self, item): 148 ''' item of extval''' 149 return item in self.slot 150 151 def __getitem__(self, index): 152 ''' return interval item''' 153 return self.slot[index] 154 155 def __setitem__(self, index, interv): 156 ''' modify interval item''' 157 if index < 0 or index >= len(self): 158 raise TimeSlotError("out of bounds") 159 self.slot[index] = TimeInterval(interv) 160 self.slot = TimeSlot._reduced(self.slot) 161 162 def __len__(self): 163 '''return the number of intervals included''' 164 return len(self.slot) 165 166 # def __repr__(self): 167 def __str__(self): 168 ''' return the type of slot and the json representation''' 169 return self.stype + '\n' + self.json(encoded=True, encode_format='json') 170 171 def __repr__(self): 172 # return self.__class__.__name__ + f'({self.slot})' 173 return self.__class__.__name__ + '(' + self.json(encoded=True, encode_format='json') + ')' 174 175 def __eq__(self, other): 176 '''equal if the slots are equals''' 177 try: 178 return self.slot == other.slot 179 except: 180 return False 181 182 def __lt__(self, other): 183 '''compare the earliest dates''' 184 return self.slot[0] < other.slot[0] 185 186 def __hash__(self): 187 return sum(hash(interv) for interv in self.slot) 188 # return hash(self.json(True)) 189 190 @property 191 def Bounds(self): 192 '''return an interval TimeSlot with the bounds of the TimeSlot object''' 193 return TimeSlot(self.bounds) 194 195 @property 196 def bounds(self): 197 '''return a tuple with the start and end dates with isoformat string''' 198 return (TimeSlot.form(self.slot[0].start), TimeSlot.form(self.slot[len(self) - 1].end)) 199 200 @classmethod 201 def cast(cls, value): 202 ''' 203 tranform a value (unique or list) in a list of `TimeSlot` 204 205 *Parameters* 206 207 - **value** : value to transform 208 209 *Returns* 210 211 - **list** : list of `TimeSlot` 212 ''' 213 if isinstance(value, list): 214 try: 215 return [cls(val) for val in value] 216 except: 217 return [cls(value)] 218 else: 219 return [cls(value)] 220 221 @property 222 def Centroid(self): 223 '''return a TimeSlot with the date corresponding to the middle of the duration''' 224 return TimeSlot(self.instant) 225 226 @property 227 def duration(self): 228 '''cumulative duration of each interval (timedelta format)''' 229 duration = datetime.timedelta() 230 for interv in self.slot: 231 duration += interv.duration 232 return duration 233 234 @staticmethod 235 def form(dtime): 236 if dtime.timetuple()[3:6] == (0, 0, 0): 237 return dtime.date().isoformat() 238 return dtime.isoformat() 239 240 @property 241 def instant(self): 242 '''return the date corresponding to the middle of the duration (datetime format)''' 243 duration = self.duration / 2 244 for interv in self.slot: 245 if duration > interv.duration: 246 duration -= interv.duration 247 else: 248 return interv.start + duration 249 250 @property 251 def middle(self): 252 '''return the date corresponding to the middle of the bounds (datetime format)''' 253 return self.bounds.instant 254 255 @property 256 def name(self): 257 ''' class name''' 258 return self.__class__.__name__ 259 260 @property 261 def interval(self): 262 '''return a list with the start and end dates (datetime format)''' 263 return [self.slot[0].start, self.slot[len(self) - 1].end] 264 265 @property 266 def stype(self): 267 '''return a string with the type of TimeSlot (instant, interval, slot)''' 268 if len(self.slot) == 1: 269 return self.slot[0].stype 270 else: 271 return 'slot' 272 273 def json(self, **kwargs): 274 ''' 275 Return json/bson structure with the list of TimeInterval. 276 277 *Parameters* 278 279 - **encoded** : defaut False - if False return dict, else return json string/bson bytes 280 - **encode_format** : defaut 'json' - return json, bson or cbor format 281 282 *Returns* : string or dict''' 283 option = {'encoded': False, 'encode_format': 'json'} | kwargs 284 if len(self) == 1: 285 js = self.slot[0].json( 286 encoded=False, encode_format=option['encode_format']) 287 else: 288 js = [interv.json( 289 encoded=False, encode_format=option['encode_format']) for interv in self.slot] 290 if option['encoded'] and option['encode_format'] == 'json': 291 return json.dumps(js, cls=TimeSlotEncoder) 292 if option['encoded'] and option['encode_format'] == 'bson': 293 return bson.encode(js) 294 return js 295 296 def link(self, other): 297 ''' 298 Return the status (string) of the link between two TimeSlot (self and other). 299 - equals : if self and other are the same 300 - disjoint : if self's intervals and other's intervals are all disjoint 301 - within : if all self's intervals are included in other's intervals 302 - contains : if all other's intervals are included in self's intervals 303 - intersects : in the others cases 304 305 *Parameters* 306 307 - **other** : TimeSlot to be compared 308 309 *Returns* 310 311 - **tuple** : (string(status), boolean(full or not))''' 312 if self.stype == 'instant': 313 point, oslot = self[0], other 314 elif other.stype == 'instant': 315 point, oslot = other[0], self 316 else: 317 point = None 318 if point is not None: 319 contains = equals = False 320 for interv in oslot: 321 contains = contains or interv.link(point) == 'contains' 322 equals = equals or interv.link(point) == 'equals' 323 if equals and not contains: 324 return ('equals', True) 325 if contains and point == other[0]: 326 return ('contains', True) 327 if contains and point == self[0]: 328 return ('within', True) 329 return ('disjoint', True) 330 else: 331 union = self + other 332 link = 'intersects' 333 full = True 334 if union.duration == self.duration == other.duration: 335 full = len(union) == len(self) == len(other) 336 link = 'equals' 337 elif union.duration == self.duration: 338 full = len(union) == len(self) 339 link = 'contains' 340 elif union.duration == other.duration: 341 full = len(union) == len(other) 342 link = 'within' 343 elif union.duration == self.duration + other.duration: 344 full = len(union) == len(self) + len(other) 345 link = 'disjoint' 346 return (link, full) 347 348 def timetuple(self, index=0, encoded=False): 349 ''' 350 Return json structure with the list of TimeInterval (timetuple filter). 351 352 *Parameters* 353 354 - **index** : integer, defaut 0 - timetuple format to apply : 355 - 0 : year 356 - 1 : month 357 - 2 : day 358 - 3 : hour 359 - 4 : minute 360 - 5 : seconds 361 - 6 : weekday 362 - 7 : yearday 363 - 8 : isdst (1 when daylight savings time is in effect, 0 when is not) 364 - **encoded** : defaut False - if True return string, else return dict 365 366 *Returns* : string or dict''' 367 if len(self) == 1: 368 js = self.slot[0].timetuple(index, False) 369 else: 370 js = [interv.timetuple(index, False) for interv in self.slot] 371 if encoded: 372 return json.dumps(js, cls=TimeSlotEncoder) 373 else: 374 return js 375 376 def union(self, other): 377 ''' Add other's values to self's values in a new TimeSlot (same as __add__)''' 378 return self.__add__(other) 379 380 @staticmethod 381 def _reduced(listinterv): 382 ''' return an ordered and non-overlapping list of TimeInterval from any TimeInterval list''' 383 if not isinstance(listinterv, list) or len(listinterv) == 0: 384 return [] 385 union = [] 386 slot = sorted(listinterv) 387 interv = slot[0] 388 i = j = 0 389 while i < len(slot): 390 for j in range(i + 1, len(slot)): 391 if interv.link(slot[j]) == 'within': 392 interv = slot[j] 393 elif interv.link(slot[j]) == 'intersects': 394 interv = interv.union(slot[j]) 395 elif interv.link(slot[j]) == 'disjoint': 396 union.append(interv) 397 interv = slot[j] 398 i = j 399 break 400 if j >= len(slot) - 1: 401 union.append(interv) 402 break 403 return union 404 405 @staticmethod 406 def _listed(idx): 407 '''transform a tuple of tuple in a list of list''' 408 if not isinstance(idx, str) and hasattr(idx, '__iter__'): 409 return [val if not isinstance(val, tuple) else TimeSlot._listed(val) for val in idx] 410 return idx
Attributes (for @property see methods) :
- slot : list of
TimeInterval
The methods defined in this class are :
dynamic value property (getters)
TimeSlot.Bounds
TimeSlot.bounds
TimeSlot.Centroid
TimeSlot.duration
TimeSlot.instant
TimeSlot.middle
TimeSlot.interval
TimeSlot.stype
instance methods
94 def __init__(self, val=None): 95 ''' 96 TimeSlot constructor. 97 98 *Parameters* 99 100 - **val** : date, interval, list of interval (default None) - with several formats 101 (tuple, list, string, datetime, TimeSlot, TimeInterval, numpy datetime64, pandas timestamp) 102 103 *Returns* : None''' 104 slot = [] 105 if isinstance(val, str): 106 try: 107 val = json.loads(val) 108 except: 109 val = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 110 # try: val = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 111 # except: val = None 112 if val == None: 113 self.slot = slot 114 return 115 val = TimeSlot._listed(val) 116 #if isinstance(val, tuple): val = list(val) 117 if isinstance(val, list) and len(val) == 2 and not isinstance(val[0], TimeInterval): 118 try: 119 slot.append(TimeInterval(val)) 120 except: 121 for interv in val: 122 slot.append(TimeInterval(interv)) 123 elif isinstance(val, list): 124 try: 125 for interv in val: 126 slot.append(TimeInterval(interv)) 127 except: 128 slot.append(TimeInterval(val)) 129 elif isinstance(val, datetime.datetime): 130 slot.append(TimeInterval(val)) 131 elif isinstance(val, TimeSlot): 132 slot = val.slot 133 elif isinstance(val, TimeInterval): 134 slot.append(val) 135 else: 136 slot.append(TimeInterval(val)) 137 self.slot = TimeSlot._reduced(slot)
TimeSlot constructor.
Parameters
- val : date, interval, list of interval (default None) - with several formats (tuple, list, string, datetime, TimeSlot, TimeInterval, numpy datetime64, pandas timestamp)
Returns : None
200 @classmethod 201 def cast(cls, value): 202 ''' 203 tranform a value (unique or list) in a list of `TimeSlot` 204 205 *Parameters* 206 207 - **value** : value to transform 208 209 *Returns* 210 211 - **list** : list of `TimeSlot` 212 ''' 213 if isinstance(value, list): 214 try: 215 return [cls(val) for val in value] 216 except: 217 return [cls(value)] 218 else: 219 return [cls(value)]
273 def json(self, **kwargs): 274 ''' 275 Return json/bson structure with the list of TimeInterval. 276 277 *Parameters* 278 279 - **encoded** : defaut False - if False return dict, else return json string/bson bytes 280 - **encode_format** : defaut 'json' - return json, bson or cbor format 281 282 *Returns* : string or dict''' 283 option = {'encoded': False, 'encode_format': 'json'} | kwargs 284 if len(self) == 1: 285 js = self.slot[0].json( 286 encoded=False, encode_format=option['encode_format']) 287 else: 288 js = [interv.json( 289 encoded=False, encode_format=option['encode_format']) for interv in self.slot] 290 if option['encoded'] and option['encode_format'] == 'json': 291 return json.dumps(js, cls=TimeSlotEncoder) 292 if option['encoded'] and option['encode_format'] == 'bson': 293 return bson.encode(js) 294 return js
Return json/bson structure with the list of TimeInterval.
Parameters
- encoded : defaut False - if False return dict, else return json string/bson bytes
- encode_format : defaut 'json' - return json, bson or cbor format
Returns : string or dict
296 def link(self, other): 297 ''' 298 Return the status (string) of the link between two TimeSlot (self and other). 299 - equals : if self and other are the same 300 - disjoint : if self's intervals and other's intervals are all disjoint 301 - within : if all self's intervals are included in other's intervals 302 - contains : if all other's intervals are included in self's intervals 303 - intersects : in the others cases 304 305 *Parameters* 306 307 - **other** : TimeSlot to be compared 308 309 *Returns* 310 311 - **tuple** : (string(status), boolean(full or not))''' 312 if self.stype == 'instant': 313 point, oslot = self[0], other 314 elif other.stype == 'instant': 315 point, oslot = other[0], self 316 else: 317 point = None 318 if point is not None: 319 contains = equals = False 320 for interv in oslot: 321 contains = contains or interv.link(point) == 'contains' 322 equals = equals or interv.link(point) == 'equals' 323 if equals and not contains: 324 return ('equals', True) 325 if contains and point == other[0]: 326 return ('contains', True) 327 if contains and point == self[0]: 328 return ('within', True) 329 return ('disjoint', True) 330 else: 331 union = self + other 332 link = 'intersects' 333 full = True 334 if union.duration == self.duration == other.duration: 335 full = len(union) == len(self) == len(other) 336 link = 'equals' 337 elif union.duration == self.duration: 338 full = len(union) == len(self) 339 link = 'contains' 340 elif union.duration == other.duration: 341 full = len(union) == len(other) 342 link = 'within' 343 elif union.duration == self.duration + other.duration: 344 full = len(union) == len(self) + len(other) 345 link = 'disjoint' 346 return (link, full)
Return the status (string) of the link between two TimeSlot (self and other).
- equals : if self and other are the same
- disjoint : if self's intervals and other's intervals are all disjoint
- within : if all self's intervals are included in other's intervals
- contains : if all other's intervals are included in self's intervals
- intersects : in the others cases
Parameters
- other : TimeSlot to be compared
Returns
- tuple : (string(status), boolean(full or not))
348 def timetuple(self, index=0, encoded=False): 349 ''' 350 Return json structure with the list of TimeInterval (timetuple filter). 351 352 *Parameters* 353 354 - **index** : integer, defaut 0 - timetuple format to apply : 355 - 0 : year 356 - 1 : month 357 - 2 : day 358 - 3 : hour 359 - 4 : minute 360 - 5 : seconds 361 - 6 : weekday 362 - 7 : yearday 363 - 8 : isdst (1 when daylight savings time is in effect, 0 when is not) 364 - **encoded** : defaut False - if True return string, else return dict 365 366 *Returns* : string or dict''' 367 if len(self) == 1: 368 js = self.slot[0].timetuple(index, False) 369 else: 370 js = [interv.timetuple(index, False) for interv in self.slot] 371 if encoded: 372 return json.dumps(js, cls=TimeSlotEncoder) 373 else: 374 return js
Return json structure with the list of TimeInterval (timetuple filter).
Parameters
- index : integer, defaut 0 - timetuple format to apply :
- 0 : year
- 1 : month
- 2 : day
- 3 : hour
- 4 : minute
- 5 : seconds
- 6 : weekday
- 7 : yearday
- 8 : isdst (1 when daylight savings time is in effect, 0 when is not)
- encoded : defaut False - if True return string, else return dict
Returns : string or dict
413class TimeInterval: # !!! interval 414 ''' 415 *Attributes (for @property see methods)* : 416 417 - **start** : datetime Object - start of `TimeInterval` 418 - **end** : datetime Object - end of `TimeInterval` 419 420 The methods defined in this class are : 421 422 *dynamic value property (getters)* 423 424 - `TimeInterval.Bounds` 425 - `TimeInterval.bounds` 426 - `TimeInterval.Centroid` 427 - `TimeInterval.duration` 428 - `TimeInterval.instant` 429 - `TimeInterval.stype` 430 431 *instance methods* 432 433 - `TimeInterval.json` 434 - `TimeInterval.link` 435 - `TimeInterval.timetuple` 436 - `TimeInterval.union` 437 ''' 438 439 def __init__(self, val=ES.nullDate): 440 ''' 441 TimeInterval constructor. 442 443 *Parameters* 444 445 - **val** : date, interval (default ES.nullDate) - with several formats 446 (list, string, datetime, TimeInterval, numpy datetime64, pandas timestamp) 447 448 *Returns* : None''' 449 self.start = self.end = ES.nullDate 450 if isinstance(val, str): 451 try: 452 sl = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 453 if sl != None: 454 self.start = self.end = sl 455 return 456 except: 457 try: 458 val = json.loads(val) 459 except: 460 val = ES.nullDate 461 if isinstance(val, list): 462 self._initInterval(val) 463 elif isinstance(val, TimeInterval): 464 self.start, self.end = val.start, val.end 465 else: 466 dat = self._initDat(val) 467 if dat != None: 468 self.start = self.end = dat 469 470 # def __repr__(self): 471 def __str__(self): 472 ''' return the type of interval and the json representation''' 473 return self.stype + '\n' + self.json(encoded=True, encode_format='json') 474 475 def __repr__(self): 476 # if self.stype == 'instant' : return self.__class__.__name__ + f'("{self.start}")' 477 # return self.__class__.__name__ + f'(["{self.start}","{self.end}"])' 478 return self.__class__.__name__ + '(' + self.json(encoded=True, encode_format='json') + ')' 479 480 def __eq__(self, other): 481 '''equal if the 'start' and 'end' dates are equals''' 482 return self.start == other.start and self.end == other.end 483 484 def __lt__(self, other): 485 '''compare the earliest dates (start)''' 486 return self.start < other.start 487 488 def __hash__(self): 489 return hash(self.start) + hash(self.end) 490 # return hash(self.json(True)) 491 492 @property 493 def bounds(self): 494 '''return a tuple with the start and end dates with isoformat string''' 495 return (TimeSlot.form(self.start), TimeSlot.form(self.end)) 496 497 @property 498 def Centroid(self): 499 '''return a TimeInterval with the date corresponding to the middle of the interval''' 500 return TimeInterval(self.instant) 501 502 @property 503 def duration(self): 504 '''duration between 'end' and 'start' date (timedelta format)''' 505 return self.end - self.start 506 507 @property 508 def instant(self): 509 '''return the date corresponding to the middle of the duration (datetime format)''' 510 return self.start + (self.end - self.start) / 2 511 512 @property 513 def stype(self): 514 '''return a string with the type of TimeInterval (instant, interval)''' 515 if self.start == self.end: 516 return 'instant' 517 return 'interval' 518 519 def json(self, encoded=False, encode_format='json'): 520 ''' 521 Return json/bson structure (date if 'instant' or [start, end] if 'interval') 522 with datetime or datetime.isoformat for dates. 523 524 *Parameters* 525 526 - **encoded** : defaut False - if True return dict, else return json string/bson bytes 527 - **encode_format** : defaut 'json' - return json, bson or cbor format 528 529 *Returns* : string or dict''' 530 if self.stype == 'instant': 531 js = self.start 532 else: 533 js = [self.start, self.end] 534 '''if self.stype == 'instant' : 535 if encode_format == 'bson': js = self.start 536 else: 537 js = TimeSlot.form(self.start) 538 elif self.stype == 'interval' : 539 if encode_format == 'bson': js = [self.start, self.end] 540 else: js = [TimeSlot.form(self.start), TimeSlot.form(self.end)]''' 541 if encoded and encode_format == 'json': 542 return json.dumps(js, cls=TimeSlotEncoder) 543 if encoded and encode_format == 'bson': 544 return bson.encode(js) 545 return js 546 547 def link(self, other): 548 ''' 549 Return the status (string) of the link between two TimeIntervals (self and other). 550 - equals : if self and other are the same 551 - disjoint : if self's interval and other's interval are disjoint 552 - within : if other's interval is included in self's interval 553 - contains : if self's interval is included in other's interval 554 - intersects : in the others cases 555 556 *Parameters* 557 558 - **other** : TimeInterval to be compared 559 560 *Returns* : string''' 561 if self.start == other.start and self.end == other.end: 562 return 'equals' 563 if self.start <= other.start and self.end >= other.end: 564 return 'contains' 565 if self.start >= other.start and self.end <= other.end: 566 return 'within' 567 if self.start <= other.end and self.end >= other.start: 568 return 'intersects' 569 return 'disjoint' 570 571 def timetuple(self, index=0, encoded=False): 572 ''' 573 Return json structure (timetuple filter). 574 575 *Parameters* 576 577 - **index** : integer, defaut 0 - timetuple format to apply : 578 - 0 : year 579 - 1 : month 580 - 2 : day 581 - 3 : hour 582 - 4 : minute 583 - 5 : seconds 584 - 6 : weekday 585 - 7 : yearday 586 - 8 : isdst (1 when daylight savings time is in effect, 0 when is not) 587 - **encoded** : defaut False - if True return string, else return dict 588 589 *Returns* : string or dict''' 590 if index not in [0, 1, 2, 3, 4, 5, 6, 7, 8]: 591 return None 592 if self.stype == 'instant': 593 js = self.start.timetuple()[index] 594 elif self.stype == 'interval': 595 js = [self.start.timetuple()[index], self.end.timetuple()[index]] 596 if encoded: 597 return json.dumps(js, cls=TimeSlotEncoder) 598 else: 599 return js 600 601 def union(self, other): 602 ''' Add other's values to self's values in a new TimeInterval 603 if self and other are not disjoint''' 604 if self.link(other) != 'disjoint': 605 return TimeInterval([min(self.start, other.start), max(self.end, other.end)]) 606 else: 607 return None 608 609 def _initInterval(self, val): 610 '''initialization of start and end dates from a list''' 611 self.start = self.end = self._initDat(val[0]) 612 if len(val) > 1: 613 self.end = self._initDat(val[1]) 614 else: 615 self.start = self.end = self._initDat(val) 616 if self.end < self.start: 617 self.start, self.end = self.end, self.start 618 619 def _initDat(self, val): 620 '''initialization of start and end dates from a unique value 621 (datetime, string, numpy.datetime64, pandas Timestamp)''' 622 if isinstance(val, datetime.datetime): 623 res = val 624 '''if val.tzinfo is None or val.tzinfo.utcoffset(val) is None: 625 res = val.astimezone(datetime.timezone.utc) 626 else: res = val''' 627 elif isinstance(val, str): 628 try: 629 res = datetime.datetime.fromisoformat(val) 630 except: 631 res = ES.nullDate 632 elif isinstance(val, numpy.datetime64): 633 res = pandas.Timestamp(val).to_pydatetime() 634 elif isinstance(val, pandas._libs.tslibs.timestamps.Timestamp): 635 res = val.to_pydatetime() 636 else: 637 raise TimeSlotError("impossible to convert in a date") 638 return TimeInterval._dattz(res) 639 640 @staticmethod 641 def _dattz(val): 642 if val.tzinfo is None or val.tzinfo.utcoffset(val) is None: 643 return val.replace(tzinfo=datetime.timezone.utc) 644 return val
Attributes (for @property see methods) :
- start : datetime Object - start of
TimeInterval
- end : datetime Object - end of
TimeInterval
The methods defined in this class are :
dynamic value property (getters)
TimeInterval.Bounds
TimeInterval.bounds
TimeInterval.Centroid
TimeInterval.duration
TimeInterval.instant
TimeInterval.stype
instance methods
439 def __init__(self, val=ES.nullDate): 440 ''' 441 TimeInterval constructor. 442 443 *Parameters* 444 445 - **val** : date, interval (default ES.nullDate) - with several formats 446 (list, string, datetime, TimeInterval, numpy datetime64, pandas timestamp) 447 448 *Returns* : None''' 449 self.start = self.end = ES.nullDate 450 if isinstance(val, str): 451 try: 452 sl = TimeInterval._dattz(datetime.datetime.fromisoformat(val)) 453 if sl != None: 454 self.start = self.end = sl 455 return 456 except: 457 try: 458 val = json.loads(val) 459 except: 460 val = ES.nullDate 461 if isinstance(val, list): 462 self._initInterval(val) 463 elif isinstance(val, TimeInterval): 464 self.start, self.end = val.start, val.end 465 else: 466 dat = self._initDat(val) 467 if dat != None: 468 self.start = self.end = dat
TimeInterval constructor.
Parameters
- val : date, interval (default ES.nullDate) - with several formats (list, string, datetime, TimeInterval, numpy datetime64, pandas timestamp)
Returns : None
519 def json(self, encoded=False, encode_format='json'): 520 ''' 521 Return json/bson structure (date if 'instant' or [start, end] if 'interval') 522 with datetime or datetime.isoformat for dates. 523 524 *Parameters* 525 526 - **encoded** : defaut False - if True return dict, else return json string/bson bytes 527 - **encode_format** : defaut 'json' - return json, bson or cbor format 528 529 *Returns* : string or dict''' 530 if self.stype == 'instant': 531 js = self.start 532 else: 533 js = [self.start, self.end] 534 '''if self.stype == 'instant' : 535 if encode_format == 'bson': js = self.start 536 else: 537 js = TimeSlot.form(self.start) 538 elif self.stype == 'interval' : 539 if encode_format == 'bson': js = [self.start, self.end] 540 else: js = [TimeSlot.form(self.start), TimeSlot.form(self.end)]''' 541 if encoded and encode_format == 'json': 542 return json.dumps(js, cls=TimeSlotEncoder) 543 if encoded and encode_format == 'bson': 544 return bson.encode(js) 545 return js
Return json/bson structure (date if 'instant' or [start, end] if 'interval') with datetime or datetime.isoformat for dates.
Parameters
- encoded : defaut False - if True return dict, else return json string/bson bytes
- encode_format : defaut 'json' - return json, bson or cbor format
Returns : string or dict
547 def link(self, other): 548 ''' 549 Return the status (string) of the link between two TimeIntervals (self and other). 550 - equals : if self and other are the same 551 - disjoint : if self's interval and other's interval are disjoint 552 - within : if other's interval is included in self's interval 553 - contains : if self's interval is included in other's interval 554 - intersects : in the others cases 555 556 *Parameters* 557 558 - **other** : TimeInterval to be compared 559 560 *Returns* : string''' 561 if self.start == other.start and self.end == other.end: 562 return 'equals' 563 if self.start <= other.start and self.end >= other.end: 564 return 'contains' 565 if self.start >= other.start and self.end <= other.end: 566 return 'within' 567 if self.start <= other.end and self.end >= other.start: 568 return 'intersects' 569 return 'disjoint'
Return the status (string) of the link between two TimeIntervals (self and other).
- equals : if self and other are the same
- disjoint : if self's interval and other's interval are disjoint
- within : if other's interval is included in self's interval
- contains : if self's interval is included in other's interval
- intersects : in the others cases
Parameters
- other : TimeInterval to be compared
Returns : string
571 def timetuple(self, index=0, encoded=False): 572 ''' 573 Return json structure (timetuple filter). 574 575 *Parameters* 576 577 - **index** : integer, defaut 0 - timetuple format to apply : 578 - 0 : year 579 - 1 : month 580 - 2 : day 581 - 3 : hour 582 - 4 : minute 583 - 5 : seconds 584 - 6 : weekday 585 - 7 : yearday 586 - 8 : isdst (1 when daylight savings time is in effect, 0 when is not) 587 - **encoded** : defaut False - if True return string, else return dict 588 589 *Returns* : string or dict''' 590 if index not in [0, 1, 2, 3, 4, 5, 6, 7, 8]: 591 return None 592 if self.stype == 'instant': 593 js = self.start.timetuple()[index] 594 elif self.stype == 'interval': 595 js = [self.start.timetuple()[index], self.end.timetuple()[index]] 596 if encoded: 597 return json.dumps(js, cls=TimeSlotEncoder) 598 else: 599 return js
Return json structure (timetuple filter).
Parameters
- index : integer, defaut 0 - timetuple format to apply :
- 0 : year
- 1 : month
- 2 : day
- 3 : hour
- 4 : minute
- 5 : seconds
- 6 : weekday
- 7 : yearday
- 8 : isdst (1 when daylight savings time is in effect, 0 when is not)
- encoded : defaut False - if True return string, else return dict
Returns : string or dict
601 def union(self, other): 602 ''' Add other's values to self's values in a new TimeInterval 603 if self and other are not disjoint''' 604 if self.link(other) != 'disjoint': 605 return TimeInterval([min(self.start, other.start), max(self.end, other.end)]) 606 else: 607 return None
Add other's values to self's values in a new TimeInterval if self and other are not disjoint
Common base class for all non-exit exceptions.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args