temporal_extent.py 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571
  1. """
  2. Temporal extent classes
  3. Usage:
  4. .. code-block:: python
  5. >>> import grass.temporal as tgis
  6. >>> from datetime import datetime
  7. >>> tgis.init()
  8. >>> t = tgis.RasterRelativeTime()
  9. >>> t = tgis.RasterAbsoluteTime()
  10. (C) 2012-2013 by the GRASS Development Team
  11. This program is free software under the GNU General Public
  12. License (>=v2). Read the file COPYING that comes with GRASS
  13. for details.
  14. :authors: Soeren Gebbert
  15. """
  16. from __future__ import print_function
  17. from .base import SQLDatabaseInterface
  18. ###############################################################################
  19. class TemporalExtent(SQLDatabaseInterface):
  20. """This is the abstract time base class for relative and absolute time
  21. objects.
  22. It abstract class implements the interface to absolute and relative time.
  23. Absolute time is represented by datetime time stamps,
  24. relative time is represented by a unit an integer value.
  25. This class implements temporal topology relationships computation
  26. after [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic].
  27. Usage:
  28. .. code-block:: python
  29. >>> init()
  30. >>> A = TemporalExtent(table="raster_absolute_time",
  31. ... ident="soil@PERMANENT", start_time=datetime(2001, 01, 01),
  32. ... end_time=datetime(2005,01,01) )
  33. >>> A.id
  34. 'soil@PERMANENT'
  35. >>> A.start_time
  36. datetime.datetime(2001, 1, 1, 0, 0)
  37. >>> A.end_time
  38. datetime.datetime(2005, 1, 1, 0, 0)
  39. >>> A.print_info()
  40. | Start time:................. 2001-01-01 00:00:00
  41. | End time:................... 2005-01-01 00:00:00
  42. >>> A.print_shell_info()
  43. start_time='2001-01-01 00:00:00'
  44. end_time='2005-01-01 00:00:00'
  45. >>> # relative time
  46. >>> A = TemporalExtent(table="raster_absolute_time",
  47. ... ident="soil@PERMANENT", start_time=0, end_time=1 )
  48. >>> A.id
  49. 'soil@PERMANENT'
  50. >>> A.start_time
  51. 0
  52. >>> A.end_time
  53. 1
  54. >>> A.print_info()
  55. | Start time:................. 0
  56. | End time:................... 1
  57. >>> A.print_shell_info()
  58. start_time='0'
  59. end_time='1'
  60. """
  61. def __init__(self, table=None, ident=None, start_time=None, end_time=None):
  62. SQLDatabaseInterface.__init__(self, table, ident)
  63. self.set_id(ident)
  64. self.set_start_time(start_time)
  65. self.set_end_time(end_time)
  66. def intersect(self, extent):
  67. """Intersect this temporal extent with the provided temporal extent and
  68. return a new temporal extent with the new start and end time
  69. :param extent: The temporal extent to intersect with
  70. :return: The new temporal extent with start and end time,
  71. or None in case of no intersection
  72. Usage:
  73. .. code-block:: python
  74. >>> A = TemporalExtent(start_time=5, end_time=6 )
  75. >>> inter = A.intersect(A)
  76. >>> inter.print_info()
  77. | Start time:................. 5
  78. | End time:................... 6
  79. >>> A = TemporalExtent(start_time=5, end_time=6 )
  80. >>> B = TemporalExtent(start_time=5, end_time=7 )
  81. >>> inter = A.intersect(B)
  82. >>> inter.print_info()
  83. | Start time:................. 5
  84. | End time:................... 6
  85. >>> inter = B.intersect(A)
  86. >>> inter.print_info()
  87. | Start time:................. 5
  88. | End time:................... 6
  89. >>> A = TemporalExtent(start_time=3, end_time=6 )
  90. >>> B = TemporalExtent(start_time=5, end_time=7 )
  91. >>> inter = A.intersect(B)
  92. >>> inter.print_info()
  93. | Start time:................. 5
  94. | End time:................... 6
  95. >>> inter = B.intersect(A)
  96. >>> inter.print_info()
  97. | Start time:................. 5
  98. | End time:................... 6
  99. >>> A = TemporalExtent(start_time=3, end_time=8 )
  100. >>> B = TemporalExtent(start_time=5, end_time=6 )
  101. >>> inter = A.intersect(B)
  102. >>> inter.print_info()
  103. | Start time:................. 5
  104. | End time:................... 6
  105. >>> inter = B.intersect(A)
  106. >>> inter.print_info()
  107. | Start time:................. 5
  108. | End time:................... 6
  109. >>> A = TemporalExtent(start_time=5, end_time=8 )
  110. >>> B = TemporalExtent(start_time=3, end_time=6 )
  111. >>> inter = A.intersect(B)
  112. >>> inter.print_info()
  113. | Start time:................. 5
  114. | End time:................... 6
  115. >>> inter = B.intersect(A)
  116. >>> inter.print_info()
  117. | Start time:................. 5
  118. | End time:................... 6
  119. >>> A = TemporalExtent(start_time=5, end_time=None )
  120. >>> B = TemporalExtent(start_time=3, end_time=6 )
  121. >>> inter = A.intersect(B)
  122. >>> inter.print_info()
  123. | Start time:................. 5
  124. | End time:................... None
  125. >>> inter = B.intersect(A)
  126. >>> inter.print_info()
  127. | Start time:................. 5
  128. | End time:................... None
  129. >>> A = TemporalExtent(start_time=5, end_time=8 )
  130. >>> B = TemporalExtent(start_time=3, end_time=4 )
  131. >>> inter = A.intersect(B)
  132. >>> print(inter)
  133. None
  134. >>> A = TemporalExtent(start_time=5, end_time=8 )
  135. >>> B = TemporalExtent(start_time=3, end_time=None )
  136. >>> inter = A.intersect(B)
  137. >>> print(inter)
  138. None
  139. """
  140. relation = self.temporal_relation(extent)
  141. if relation == "after" or relation == "before":
  142. return None
  143. if self.D["end_time"] is None:
  144. return TemporalExtent(start_time=self.D["start_time"])
  145. if extent.D["end_time"] is None:
  146. return TemporalExtent(start_time=extent.D["start_time"])
  147. start = None
  148. end = None
  149. if self.D["start_time"] > extent.D["start_time"]:
  150. start = self.D["start_time"]
  151. else:
  152. start = extent.D["start_time"]
  153. if self.D["end_time"] > extent.D["end_time"]:
  154. end = extent.D["end_time"]
  155. else:
  156. end = self.D["end_time"]
  157. if issubclass(type(self), RelativeTemporalExtent):
  158. return RelativeTemporalExtent(
  159. start_time=start, end_time=end, unit=self.get_unit()
  160. )
  161. elif issubclass(type(self), AbsoluteTemporalExtent):
  162. return AbsoluteTemporalExtent(start_time=start, end_time=end)
  163. elif issubclass(type(self), TemporalExtent):
  164. return TemporalExtent(start_time=start, end_time=end)
  165. def disjoint_union(self, extent):
  166. """Creates a disjoint union with this temporal extent and the provided one.
  167. Return a new temporal extent with the new start and end time.
  168. :param extent: The temporal extent to create a union with
  169. :return: The new temporal extent with start and end time
  170. Usage:
  171. .. code-block:: python
  172. >>> A = TemporalExtent(start_time=5, end_time=6 )
  173. >>> inter = A.intersect(A)
  174. >>> inter.print_info()
  175. | Start time:................. 5
  176. | End time:................... 6
  177. >>> A = TemporalExtent(start_time=5, end_time=6 )
  178. >>> B = TemporalExtent(start_time=5, end_time=7 )
  179. >>> inter = A.disjoint_union(B)
  180. >>> inter.print_info()
  181. | Start time:................. 5
  182. | End time:................... 7
  183. >>> inter = B.disjoint_union(A)
  184. >>> inter.print_info()
  185. | Start time:................. 5
  186. | End time:................... 7
  187. >>> A = TemporalExtent(start_time=3, end_time=6 )
  188. >>> B = TemporalExtent(start_time=5, end_time=7 )
  189. >>> inter = A.disjoint_union(B)
  190. >>> inter.print_info()
  191. | Start time:................. 3
  192. | End time:................... 7
  193. >>> inter = B.disjoint_union(A)
  194. >>> inter.print_info()
  195. | Start time:................. 3
  196. | End time:................... 7
  197. >>> A = TemporalExtent(start_time=3, end_time=8 )
  198. >>> B = TemporalExtent(start_time=5, end_time=6 )
  199. >>> inter = A.disjoint_union(B)
  200. >>> inter.print_info()
  201. | Start time:................. 3
  202. | End time:................... 8
  203. >>> inter = B.disjoint_union(A)
  204. >>> inter.print_info()
  205. | Start time:................. 3
  206. | End time:................... 8
  207. >>> A = TemporalExtent(start_time=5, end_time=8 )
  208. >>> B = TemporalExtent(start_time=3, end_time=6 )
  209. >>> inter = A.disjoint_union(B)
  210. >>> inter.print_info()
  211. | Start time:................. 3
  212. | End time:................... 8
  213. >>> inter = B.disjoint_union(A)
  214. >>> inter.print_info()
  215. | Start time:................. 3
  216. | End time:................... 8
  217. >>> A = TemporalExtent(start_time=5, end_time=None )
  218. >>> B = TemporalExtent(start_time=3, end_time=6 )
  219. >>> inter = A.disjoint_union(B)
  220. >>> inter.print_info()
  221. | Start time:................. 3
  222. | End time:................... 6
  223. >>> inter = B.disjoint_union(A)
  224. >>> inter.print_info()
  225. | Start time:................. 3
  226. | End time:................... 6
  227. >>> A = TemporalExtent(start_time=5, end_time=8 )
  228. >>> B = TemporalExtent(start_time=3, end_time=4 )
  229. >>> inter = A.disjoint_union(B)
  230. >>> inter.print_info()
  231. | Start time:................. 3
  232. | End time:................... 8
  233. >>> inter = B.disjoint_union(A)
  234. >>> inter.print_info()
  235. | Start time:................. 3
  236. | End time:................... 8
  237. >>> A = TemporalExtent(start_time=5, end_time=8 )
  238. >>> B = TemporalExtent(start_time=3, end_time=None )
  239. >>> inter = A.disjoint_union(B)
  240. >>> inter.print_info()
  241. | Start time:................. 3
  242. | End time:................... 8
  243. >>> inter = B.disjoint_union(A)
  244. >>> inter.print_info()
  245. | Start time:................. 3
  246. | End time:................... 8
  247. >>> A = TemporalExtent(start_time=5, end_time=None )
  248. >>> B = TemporalExtent(start_time=3, end_time=8 )
  249. >>> inter = A.disjoint_union(B)
  250. >>> inter.print_info()
  251. | Start time:................. 3
  252. | End time:................... 8
  253. >>> inter = B.disjoint_union(A)
  254. >>> inter.print_info()
  255. | Start time:................. 3
  256. | End time:................... 8
  257. >>> A = TemporalExtent(start_time=5, end_time=None )
  258. >>> B = TemporalExtent(start_time=3, end_time=None )
  259. >>> inter = A.disjoint_union(B)
  260. >>> inter.print_info()
  261. | Start time:................. 3
  262. | End time:................... 5
  263. >>> inter = B.disjoint_union(A)
  264. >>> inter.print_info()
  265. | Start time:................. 3
  266. | End time:................... 5
  267. >>> A = RelativeTemporalExtent(start_time=5, end_time=None, unit="years" )
  268. >>> B = RelativeTemporalExtent(start_time=3, end_time=None, unit="years" )
  269. >>> inter = A.disjoint_union(B)
  270. >>> inter.print_info()
  271. +-------------------- Relative time -----------------------------------------+
  272. | Start time:................. 3
  273. | End time:................... 5
  274. | Relative time unit:......... years
  275. >>> inter = B.disjoint_union(A)
  276. >>> inter.print_info()
  277. +-------------------- Relative time -----------------------------------------+
  278. | Start time:................. 3
  279. | End time:................... 5
  280. | Relative time unit:......... years
  281. >>> from datetime import datetime as dt
  282. >>> A = AbsoluteTemporalExtent(start_time=dt(2001,1,10), end_time=dt(2003,1,1))
  283. >>> B = AbsoluteTemporalExtent(start_time=dt(2005,1,10), end_time=dt(2008,1,1))
  284. >>> inter = A.disjoint_union(B)
  285. >>> inter.print_info()
  286. +-------------------- Absolute time -----------------------------------------+
  287. | Start time:................. 2001-01-10 00:00:00
  288. | End time:................... 2008-01-01 00:00:00
  289. >>> inter = B.disjoint_union(A)
  290. >>> inter.print_info()
  291. +-------------------- Absolute time -----------------------------------------+
  292. | Start time:................. 2001-01-10 00:00:00
  293. | End time:................... 2008-01-01 00:00:00
  294. """
  295. start = None
  296. end = None
  297. if self.D["start_time"] < extent.D["start_time"]:
  298. start = self.D["start_time"]
  299. else:
  300. start = extent.D["start_time"]
  301. # End time handling
  302. if self.D["end_time"] is None and extent.D["end_time"] is None:
  303. if self.D["start_time"] > extent.D["start_time"]:
  304. end = self.D["start_time"]
  305. else:
  306. end = extent.D["start_time"]
  307. elif self.D["end_time"] is None:
  308. if self.D["start_time"] > extent.D["end_time"]:
  309. end = self.D["start_time"]
  310. else:
  311. end = extent.D["end_time"]
  312. elif extent.D["end_time"] is None:
  313. if self.D["end_time"] > extent.D["start_time"]:
  314. end = self.D["end_time"]
  315. else:
  316. end = extent.D["start_time"]
  317. elif self.D["end_time"] < extent.D["end_time"]:
  318. end = extent.D["end_time"]
  319. else:
  320. end = self.D["end_time"]
  321. if issubclass(type(self), RelativeTemporalExtent):
  322. return RelativeTemporalExtent(
  323. start_time=start, end_time=end, unit=self.get_unit()
  324. )
  325. elif issubclass(type(self), AbsoluteTemporalExtent):
  326. return AbsoluteTemporalExtent(start_time=start, end_time=end)
  327. elif issubclass(type(self), TemporalExtent):
  328. return TemporalExtent(start_time=start, end_time=end)
  329. def union(self, extent):
  330. """Creates a union with this temporal extent and the provided one.
  331. Return a new temporal extent with the new start and end time.
  332. :param extent: The temporal extent to create a union with
  333. :return: The new temporal extent with start and end time,
  334. or None in case the temporal extents are unrelated
  335. (before or after)
  336. .. code-block:: python
  337. >>> A = TemporalExtent(start_time=5, end_time=8 )
  338. >>> B = TemporalExtent(start_time=3, end_time=4 )
  339. >>> inter = A.intersect(B)
  340. >>> print(inter)
  341. None
  342. >>> A = TemporalExtent(start_time=5, end_time=8 )
  343. >>> B = TemporalExtent(start_time=3, end_time=None )
  344. >>> inter = A.intersect(B)
  345. >>> print(inter)
  346. None
  347. """
  348. relation = self.temporal_relation(extent)
  349. if relation == "after" or relation == "before":
  350. return None
  351. return self.disjoint_union(extent)
  352. def starts(self, extent):
  353. """Return True if this temporal extent (A) starts at the start of the
  354. provided temporal extent (B) and finishes within it
  355. ::
  356. A |-----|
  357. B |---------|
  358. :param extent: The temporal extent object with which this extent
  359. starts
  360. Usage:
  361. .. code-block:: python
  362. >>> A = TemporalExtent(start_time=5, end_time=6 )
  363. >>> B = TemporalExtent(start_time=5, end_time=7 )
  364. >>> A.starts(B)
  365. True
  366. >>> B.starts(A)
  367. False
  368. """
  369. if self.D["end_time"] is None or extent.D["end_time"] is None:
  370. return False
  371. if (
  372. self.D["start_time"] == extent.D["start_time"]
  373. and self.D["end_time"] < extent.D["end_time"]
  374. ):
  375. return True
  376. else:
  377. return False
  378. def started(self, extent):
  379. """Return True if this temporal extent (A) started at the start of the
  380. provided temporal extent (B) and finishes after it
  381. ::
  382. A |---------|
  383. B |-----|
  384. :param extent: The temporal extent object with which this extent
  385. started
  386. Usage:
  387. .. code-block:: python
  388. >>> A = TemporalExtent(start_time=5, end_time=7 )
  389. >>> B = TemporalExtent(start_time=5, end_time=6 )
  390. >>> A.started(B)
  391. True
  392. >>> B.started(A)
  393. False
  394. """
  395. if self.D["end_time"] is None or extent.D["end_time"] is None:
  396. return False
  397. if (
  398. self.D["start_time"] == extent.D["start_time"]
  399. and self.D["end_time"] > extent.D["end_time"]
  400. ):
  401. return True
  402. else:
  403. return False
  404. def finishes(self, extent):
  405. """Return True if this temporal extent (A) starts after the start of
  406. the provided temporal extent (B) and finishes with it
  407. ::
  408. A |-----|
  409. B |---------|
  410. :param extent: The temporal extent object with which this extent
  411. finishes
  412. Usage:
  413. .. code-block:: python
  414. >>> A = TemporalExtent(start_time=6, end_time=7 )
  415. >>> B = TemporalExtent(start_time=5, end_time=7 )
  416. >>> A.finishes(B)
  417. True
  418. >>> B.finishes(A)
  419. False
  420. """
  421. if self.D["end_time"] is None or extent.D["end_time"] is None:
  422. return False
  423. if (
  424. self.D["end_time"] == extent.D["end_time"]
  425. and self.D["start_time"] > extent.D["start_time"]
  426. ):
  427. return True
  428. else:
  429. return False
  430. def finished(self, extent):
  431. """Return True if this temporal extent (A) starts before the start of
  432. the provided temporal extent (B) and finishes with it
  433. ::
  434. A |---------|
  435. B |-----|
  436. :param extent: The temporal extent object with which this extent
  437. finishes
  438. Usage:
  439. .. code-block:: python
  440. >>> A = TemporalExtent(start_time=5, end_time=7 )
  441. >>> B = TemporalExtent(start_time=6, end_time=7 )
  442. >>> A.finished(B)
  443. True
  444. >>> B.finished(A)
  445. False
  446. """
  447. if self.D["end_time"] is None or extent.D["end_time"] is None:
  448. return False
  449. if (
  450. self.D["end_time"] == extent.D["end_time"]
  451. and self.D["start_time"] < extent.D["start_time"]
  452. ):
  453. return True
  454. else:
  455. return False
  456. def after(self, extent):
  457. """Return True if this temporal extent (A) is located after the
  458. provided temporal extent (B)
  459. ::
  460. A |---------|
  461. B |---------|
  462. :param extent: The temporal extent object that is located before
  463. this extent
  464. Usage:
  465. .. code-block:: python
  466. >>> A = TemporalExtent(start_time=8, end_time=9 )
  467. >>> B = TemporalExtent(start_time=6, end_time=7 )
  468. >>> A.after(B)
  469. True
  470. >>> B.after(A)
  471. False
  472. """
  473. if extent.D["end_time"] is None:
  474. if self.D["start_time"] > extent.D["start_time"]:
  475. return True
  476. else:
  477. return False
  478. if self.D["start_time"] > extent.D["end_time"]:
  479. return True
  480. else:
  481. return False
  482. def before(self, extent):
  483. """Return True if this temporal extent (A) is located before the
  484. provided temporal extent (B)
  485. ::
  486. A |---------|
  487. B |---------|
  488. :param extent: The temporal extent object that is located after
  489. this extent
  490. Usage:
  491. .. code-block:: python
  492. >>> A = TemporalExtent(start_time=6, end_time=7 )
  493. >>> B = TemporalExtent(start_time=8, end_time=9 )
  494. >>> A.before(B)
  495. True
  496. >>> B.before(A)
  497. False
  498. """
  499. if self.D["end_time"] is None:
  500. if self.D["start_time"] < extent.D["start_time"]:
  501. return True
  502. else:
  503. return False
  504. if self.D["end_time"] < extent.D["start_time"]:
  505. return True
  506. else:
  507. return False
  508. def adjacent(self, extent):
  509. """Return True if this temporal extent (A) is a meeting neighbor the
  510. provided temporal extent (B)
  511. ::
  512. A |---------|
  513. B |---------|
  514. A |---------|
  515. B |---------|
  516. :param extent: The temporal extent object that is a meeting neighbor
  517. of this extent
  518. Usage:
  519. .. code-block:: python
  520. >>> A = TemporalExtent(start_time=5, end_time=7 )
  521. >>> B = TemporalExtent(start_time=7, end_time=9 )
  522. >>> A.adjacent(B)
  523. True
  524. >>> B.adjacent(A)
  525. True
  526. >>> A = TemporalExtent(start_time=5, end_time=7 )
  527. >>> B = TemporalExtent(start_time=3, end_time=5 )
  528. >>> A.adjacent(B)
  529. True
  530. >>> B.adjacent(A)
  531. True
  532. """
  533. if self.D["end_time"] is None and extent.D["end_time"] is None:
  534. return False
  535. if (self.D["start_time"] == extent.D["end_time"]) or (
  536. self.D["end_time"] == extent.D["start_time"]
  537. ):
  538. return True
  539. else:
  540. return False
  541. def follows(self, extent):
  542. """Return True if this temporal extent (A) follows the
  543. provided temporal extent (B)
  544. ::
  545. A |---------|
  546. B |---------|
  547. :param extent: The temporal extent object that is the predecessor
  548. of this extent
  549. Usage:
  550. .. code-block:: python
  551. >>> A = TemporalExtent(start_time=5, end_time=7 )
  552. >>> B = TemporalExtent(start_time=3, end_time=5 )
  553. >>> A.follows(B)
  554. True
  555. >>> B.follows(A)
  556. False
  557. """
  558. if extent.D["end_time"] is None:
  559. return False
  560. if self.D["start_time"] == extent.D["end_time"]:
  561. return True
  562. else:
  563. return False
  564. def precedes(self, extent):
  565. """Return True if this temporal extent (A) precedes the provided
  566. temporal extent (B)
  567. ::
  568. A |---------|
  569. B |---------|
  570. :param extent: The temporal extent object that is the successor
  571. of this extent
  572. Usage:
  573. .. code-block:: python
  574. >>> A = TemporalExtent(start_time=5, end_time=7 )
  575. >>> B = TemporalExtent(start_time=7, end_time=9 )
  576. >>> A.precedes(B)
  577. True
  578. >>> B.precedes(A)
  579. False
  580. """
  581. if self.D["end_time"] is None:
  582. return False
  583. if self.D["end_time"] == extent.D["start_time"]:
  584. return True
  585. else:
  586. return False
  587. def during(self, extent):
  588. """Return True if this temporal extent (A) is located during the provided
  589. temporal extent (B)
  590. ::
  591. A |-------|
  592. B |---------|
  593. :param extent: The temporal extent object that contains this extent
  594. Usage:
  595. .. code-block:: python
  596. >>> A = TemporalExtent(start_time=5, end_time=7 )
  597. >>> B = TemporalExtent(start_time=4, end_time=9 )
  598. >>> A.during(B)
  599. True
  600. >>> B.during(A)
  601. False
  602. """
  603. # Check single point of time in interval
  604. if extent.D["end_time"] is None:
  605. return False
  606. # Check single point of time in interval
  607. if self.D["end_time"] is None:
  608. if (
  609. self.D["start_time"] >= extent.D["start_time"]
  610. and self.D["start_time"] < extent.D["end_time"]
  611. ):
  612. return True
  613. else:
  614. return False
  615. if (
  616. self.D["start_time"] > extent.D["start_time"]
  617. and self.D["end_time"] < extent.D["end_time"]
  618. ):
  619. return True
  620. else:
  621. return False
  622. def contains(self, extent):
  623. """Return True if this temporal extent (A) contains the provided
  624. temporal extent (B)
  625. ::
  626. A |---------|
  627. B |-------|
  628. :param extent: The temporal extent object that is located
  629. during this extent
  630. Usage:
  631. .. code-block:: python
  632. >>> A = TemporalExtent(start_time=4, end_time=9 )
  633. >>> B = TemporalExtent(start_time=5, end_time=8 )
  634. >>> A.contains(B)
  635. True
  636. >>> B.contains(A)
  637. False
  638. """
  639. # Check single point of time in interval
  640. if self.D["end_time"] is None:
  641. return False
  642. # Check single point of time in interval
  643. if extent.D["end_time"] is None:
  644. if (
  645. self.D["start_time"] <= extent.D["start_time"]
  646. and self.D["end_time"] > extent.D["start_time"]
  647. ):
  648. return True
  649. else:
  650. return False
  651. if (
  652. self.D["start_time"] < extent.D["start_time"]
  653. and self.D["end_time"] > extent.D["end_time"]
  654. ):
  655. return True
  656. else:
  657. return False
  658. def equal(self, extent):
  659. """Return True if this temporal extent (A) is equal to the provided
  660. temporal extent (B)
  661. ::
  662. A |---------|
  663. B |---------|
  664. :param extent: The temporal extent object that is equal
  665. during this extent
  666. Usage:
  667. .. code-block:: python
  668. >>> A = TemporalExtent(start_time=5, end_time=6 )
  669. >>> B = TemporalExtent(start_time=5, end_time=6 )
  670. >>> A.equal(B)
  671. True
  672. >>> B.equal(A)
  673. True
  674. """
  675. if self.D["end_time"] is None and extent.D["end_time"] is None:
  676. if self.D["start_time"] == extent.D["start_time"]:
  677. return True
  678. else:
  679. return False
  680. if self.D["end_time"] is None or extent.D["end_time"] is None:
  681. return False
  682. if (
  683. self.D["start_time"] == extent.D["start_time"]
  684. and self.D["end_time"] == extent.D["end_time"]
  685. ):
  686. return True
  687. else:
  688. return False
  689. def overlaps(self, extent):
  690. """Return True if this temporal extent (A) overlapped the provided
  691. temporal extent (B)
  692. ::
  693. A |---------|
  694. B |---------|
  695. :param extent: The temporal extent object that is overlaps
  696. this extent
  697. Usage:
  698. .. code-block:: python
  699. >>> A = TemporalExtent(start_time=5, end_time=7 )
  700. >>> B = TemporalExtent(start_time=6, end_time=8 )
  701. >>> A.overlaps(B)
  702. True
  703. >>> B.overlaps(A)
  704. False
  705. >>> A = TemporalExtent(start_time=5, end_time=6 )
  706. >>> B = TemporalExtent(start_time=6, end_time=8 )
  707. >>> A.overlaps(B)
  708. False
  709. >>> B.overlaps(A)
  710. False
  711. """
  712. if self.D["end_time"] is None or extent.D["end_time"] is None:
  713. return False
  714. if (
  715. self.D["start_time"] < extent.D["start_time"]
  716. and self.D["end_time"] < extent.D["end_time"]
  717. and self.D["end_time"] > extent.D["start_time"]
  718. ):
  719. return True
  720. else:
  721. return False
  722. def overlapped(self, extent):
  723. """Return True if this temporal extent (A) overlapps the provided
  724. temporal extent (B)
  725. ::
  726. A |---------|
  727. B |---------|
  728. :param extent: The temporal extent object that is overlapped
  729. this extent
  730. Usage:
  731. .. code-block:: python
  732. >>> A = TemporalExtent(start_time=6, end_time=8 )
  733. >>> B = TemporalExtent(start_time=5, end_time=7 )
  734. >>> A.overlapped(B)
  735. True
  736. >>> B.overlapped(A)
  737. False
  738. >>> A = TemporalExtent(start_time=6, end_time=8 )
  739. >>> B = TemporalExtent(start_time=5, end_time=6 )
  740. >>> A.overlapped(B)
  741. False
  742. >>> B.overlapped(A)
  743. False
  744. """
  745. if self.D["end_time"] is None or extent.D["end_time"] is None:
  746. return False
  747. if (
  748. self.D["start_time"] > extent.D["start_time"]
  749. and self.D["end_time"] > extent.D["end_time"]
  750. and self.D["start_time"] < extent.D["end_time"]
  751. ):
  752. return True
  753. else:
  754. return False
  755. def temporal_relation(self, extent):
  756. """Returns the temporal relation between temporal objects
  757. Temporal relationships are implemented after
  758. [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
  759. The following temporal relationships are supported:
  760. - equal
  761. - during
  762. - contains
  763. - overlaps
  764. - overlapped
  765. - after
  766. - before
  767. - starts
  768. - finishes
  769. - started
  770. - finished
  771. - follows
  772. - precedes
  773. :param extent: The temporal extent
  774. :return: The name of the temporal relation or None if no relation
  775. found
  776. """
  777. # First check for correct time
  778. if "start_time" not in self.D:
  779. return None
  780. if "end_time" not in self.D:
  781. return None
  782. if "start_time" not in extent.D:
  783. return None
  784. if "end_time" not in extent.D:
  785. return None
  786. # Return None if the start_time is undefined
  787. if self.D["start_time"] is None or extent.D["start_time"] is None:
  788. return None
  789. if self.equal(extent):
  790. return "equal"
  791. if self.during(extent):
  792. return "during"
  793. if self.contains(extent):
  794. return "contains"
  795. if self.overlaps(extent):
  796. return "overlaps"
  797. if self.overlapped(extent):
  798. return "overlapped"
  799. if self.after(extent):
  800. return "after"
  801. if self.before(extent):
  802. return "before"
  803. if self.starts(extent):
  804. return "starts"
  805. if self.finishes(extent):
  806. return "finishes"
  807. if self.started(extent):
  808. return "started"
  809. if self.finished(extent):
  810. return "finished"
  811. if self.follows(extent):
  812. return "follows"
  813. if self.precedes(extent):
  814. return "precedes"
  815. return None
  816. def set_id(self, ident):
  817. """Convenient method to set the unique identifier (primary key)"""
  818. self.ident = ident
  819. self.D["id"] = ident
  820. def set_start_time(self, start_time):
  821. """Set the valid start time of the extent"""
  822. self.D["start_time"] = start_time
  823. def set_end_time(self, end_time):
  824. """Set the valid end time of the extent"""
  825. self.D["end_time"] = end_time
  826. def get_id(self):
  827. """Convenient method to get the unique identifier (primary key)
  828. :return: None if not found
  829. """
  830. if "id" in self.D:
  831. return self.D["id"]
  832. else:
  833. return None
  834. def get_start_time(self):
  835. """Get the valid start time of the extent
  836. :return: None if not found"""
  837. if "start_time" in self.D:
  838. return self.D["start_time"]
  839. else:
  840. return None
  841. def get_end_time(self):
  842. """Get the valid end time of the extent
  843. :return: None if not found"""
  844. if "end_time" in self.D:
  845. return self.D["end_time"]
  846. else:
  847. return None
  848. # Set the properties
  849. id = property(fget=get_id, fset=set_id)
  850. start_time = property(fget=get_start_time, fset=set_start_time)
  851. end_time = property(fget=get_end_time, fset=set_end_time)
  852. def print_info(self):
  853. """Print information about this class in human readable style"""
  854. # 0123456789012345678901234567890
  855. print(" | Start time:................. " + str(self.get_start_time()))
  856. print(" | End time:................... " + str(self.get_end_time()))
  857. def print_shell_info(self):
  858. """Print information about this class in shell style"""
  859. print("start_time='{}'".format(str(self.get_start_time())))
  860. print("end_time='{}'".format(str(self.get_end_time())))
  861. ###############################################################################
  862. class AbsoluteTemporalExtent(TemporalExtent):
  863. """This is the absolute time class for all maps and spacetime datasets
  864. start_time and end_time must be of type datetime
  865. """
  866. def __init__(self, table=None, ident=None, start_time=None, end_time=None):
  867. TemporalExtent.__init__(self, table, ident, start_time, end_time)
  868. def print_info(self):
  869. """Print information about this class in human readable style"""
  870. # 0123456789012345678901234567890
  871. print(
  872. " +-------------------- Absolute time -----------------------------------------+"
  873. )
  874. TemporalExtent.print_info(self)
  875. def print_shell_info(self):
  876. """Print information about this class in shell style"""
  877. TemporalExtent.print_shell_info(self)
  878. ###############################################################################
  879. class RasterAbsoluteTime(AbsoluteTemporalExtent):
  880. def __init__(self, ident=None, start_time=None, end_time=None):
  881. AbsoluteTemporalExtent.__init__(
  882. self, "raster_absolute_time", ident, start_time, end_time
  883. )
  884. class Raster3DAbsoluteTime(AbsoluteTemporalExtent):
  885. def __init__(self, ident=None, start_time=None, end_time=None):
  886. AbsoluteTemporalExtent.__init__(
  887. self, "raster3d_absolute_time", ident, start_time, end_time
  888. )
  889. class VectorAbsoluteTime(AbsoluteTemporalExtent):
  890. def __init__(self, ident=None, start_time=None, end_time=None):
  891. AbsoluteTemporalExtent.__init__(
  892. self, "vector_absolute_time", ident, start_time, end_time
  893. )
  894. ###############################################################################
  895. class STDSAbsoluteTime(AbsoluteTemporalExtent):
  896. """This class implements the absolute time extent for space time dataset
  897. In addition to the existing functionality the granularity and the
  898. map_time are added.
  899. Usage:
  900. .. code-block:: python
  901. >>> init()
  902. >>> A = STDSAbsoluteTime(table="strds_absolute_time",
  903. ... ident="strds@PERMANENT", start_time=datetime(2001, 01, 01),
  904. ... end_time=datetime(2005,01,01), granularity="1 days",
  905. ... map_time="interval")
  906. >>> A.id
  907. 'strds@PERMANENT'
  908. >>> A.start_time
  909. datetime.datetime(2001, 1, 1, 0, 0)
  910. >>> A.end_time
  911. datetime.datetime(2005, 1, 1, 0, 0)
  912. >>> A.granularity
  913. '1 days'
  914. >>> A.map_time
  915. 'interval'
  916. >>> A.print_info()
  917. +-------------------- Absolute time -----------------------------------------+
  918. | Start time:................. 2001-01-01 00:00:00
  919. | End time:................... 2005-01-01 00:00:00
  920. | Granularity:................ 1 days
  921. | Temporal type of maps:...... interval
  922. >>> A.print_shell_info()
  923. start_time='2001-01-01 00:00:00'
  924. end_time='2005-01-01 00:00:00'
  925. granularity='1 days'
  926. map_time=interval
  927. """
  928. def __init__(
  929. self,
  930. table=None,
  931. ident=None,
  932. start_time=None,
  933. end_time=None,
  934. granularity=None,
  935. map_time=None,
  936. ):
  937. AbsoluteTemporalExtent.__init__(self, table, ident, start_time, end_time)
  938. self.set_granularity(granularity)
  939. self.set_map_time(map_time)
  940. def set_granularity(self, granularity):
  941. """Set the granularity of the space time dataset"""
  942. self.D["granularity"] = granularity
  943. def set_map_time(self, map_time):
  944. """Set the type of the map time
  945. Registered maps may have different types of time:
  946. - Single point of time "point"
  947. - Time intervals "interval"
  948. - Single point and interval time "mixed"
  949. This variable will be set automatically when maps are registered.
  950. """
  951. self.D["map_time"] = map_time
  952. def get_granularity(self):
  953. """Get the granularity of the space time dataset
  954. :return: None if not found"""
  955. if "granularity" in self.D:
  956. return self.D["granularity"]
  957. else:
  958. return None
  959. def get_map_time(self):
  960. """Get the type of the map time
  961. Registered maps may have different types of time:
  962. - Single point of time "point"
  963. - Time intervals "interval"
  964. - Single point and interval time "mixed"
  965. This variable will be set automatically when maps are registered.
  966. """
  967. if "map_time" in self.D:
  968. return self.D["map_time"]
  969. else:
  970. return None
  971. # Properties
  972. granularity = property(fget=get_granularity, fset=set_granularity)
  973. map_time = property(fget=get_map_time, fset=set_map_time)
  974. def print_info(self):
  975. """Print information about this class in human readable style"""
  976. AbsoluteTemporalExtent.print_info(self)
  977. # 0123456789012345678901234567890
  978. print(" | Granularity:................ " + str(self.get_granularity()))
  979. print(" | Temporal type of maps:...... " + str(self.get_map_time()))
  980. def print_shell_info(self):
  981. """Print information about this class in shell style"""
  982. AbsoluteTemporalExtent.print_shell_info(self)
  983. print("granularity='{}'".format(str(self.get_granularity())))
  984. print("map_time=" + str(self.get_map_time()))
  985. ###############################################################################
  986. class STRDSAbsoluteTime(STDSAbsoluteTime):
  987. def __init__(self, ident=None, start_time=None, end_time=None, granularity=None):
  988. STDSAbsoluteTime.__init__(
  989. self, "strds_absolute_time", ident, start_time, end_time, granularity
  990. )
  991. class STR3DSAbsoluteTime(STDSAbsoluteTime):
  992. def __init__(self, ident=None, start_time=None, end_time=None, granularity=None):
  993. STDSAbsoluteTime.__init__(
  994. self, "str3ds_absolute_time", ident, start_time, end_time, granularity
  995. )
  996. class STVDSAbsoluteTime(STDSAbsoluteTime):
  997. def __init__(self, ident=None, start_time=None, end_time=None, granularity=None):
  998. STDSAbsoluteTime.__init__(
  999. self, "stvds_absolute_time", ident, start_time, end_time, granularity
  1000. )
  1001. ###############################################################################
  1002. class RelativeTemporalExtent(TemporalExtent):
  1003. """This is the relative time class for all maps and space time datasets
  1004. start_time and end_time must be of type integer
  1005. Usage:
  1006. .. code-block:: python
  1007. >>> init()
  1008. >>> A = RelativeTemporalExtent(table="raster_relative_time",
  1009. ... ident="soil@PERMANENT", start_time=0, end_time=1, unit="years")
  1010. >>> A.id
  1011. 'soil@PERMANENT'
  1012. >>> A.start_time
  1013. 0
  1014. >>> A.end_time
  1015. 1
  1016. >>> A.unit
  1017. 'years'
  1018. >>> A.print_info()
  1019. +-------------------- Relative time -----------------------------------------+
  1020. | Start time:................. 0
  1021. | End time:................... 1
  1022. | Relative time unit:......... years
  1023. >>> A.print_shell_info()
  1024. start_time='0'
  1025. end_time='1'
  1026. unit=years
  1027. """
  1028. def __init__(
  1029. self, table=None, ident=None, start_time=None, end_time=None, unit=None
  1030. ):
  1031. TemporalExtent.__init__(self, table, ident, start_time, end_time)
  1032. self.set_unit(unit)
  1033. def set_unit(self, unit):
  1034. """Set the unit of the relative time. Valid units are:
  1035. - years
  1036. - months
  1037. - days
  1038. - hours
  1039. - minutes
  1040. - seconds
  1041. """
  1042. self.D["unit"] = unit
  1043. def get_unit(self):
  1044. """Get the unit of the relative time
  1045. :return: None if not found"""
  1046. if "unit" in self.D:
  1047. return self.D["unit"]
  1048. else:
  1049. return None
  1050. def temporal_relation(self, map):
  1051. """Returns the temporal relation between temporal objects
  1052. Temporal relationships are implemented after
  1053. [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
  1054. """
  1055. # Check units for relative time
  1056. if "unit" not in self.D:
  1057. return None
  1058. if "unit" not in map.D:
  1059. return None
  1060. # Units must be equal
  1061. if self.D["unit"] != map.D["unit"]:
  1062. return None
  1063. return TemporalExtent.temporal_relation(self, map)
  1064. # Properties
  1065. unit = property(fget=get_unit, fset=set_unit)
  1066. def print_info(self):
  1067. """Print information about this class in human readable style"""
  1068. # 0123456789012345678901234567890
  1069. print(
  1070. " +-------------------- Relative time -----------------------------------------+"
  1071. )
  1072. TemporalExtent.print_info(self)
  1073. print(" | Relative time unit:......... " + str(self.get_unit()))
  1074. def print_shell_info(self):
  1075. """Print information about this class in shell style"""
  1076. TemporalExtent.print_shell_info(self)
  1077. print("unit=" + str(self.get_unit()))
  1078. ###############################################################################
  1079. class RasterRelativeTime(RelativeTemporalExtent):
  1080. def __init__(self, ident=None, start_time=None, end_time=None, unit=None):
  1081. RelativeTemporalExtent.__init__(
  1082. self, "raster_relative_time", ident, start_time, end_time, unit
  1083. )
  1084. class Raster3DRelativeTime(RelativeTemporalExtent):
  1085. def __init__(self, ident=None, start_time=None, end_time=None, unit=None):
  1086. RelativeTemporalExtent.__init__(
  1087. self, "raster3d_relative_time", ident, start_time, end_time, unit
  1088. )
  1089. class VectorRelativeTime(RelativeTemporalExtent):
  1090. def __init__(self, ident=None, start_time=None, end_time=None, unit=None):
  1091. RelativeTemporalExtent.__init__(
  1092. self, "vector_relative_time", ident, start_time, end_time, unit
  1093. )
  1094. ###############################################################################
  1095. class STDSRelativeTime(RelativeTemporalExtent):
  1096. """This is the relative time class for all maps and space time datasets
  1097. start_time and end_time must be of type integer
  1098. Usage:
  1099. .. code-block:: python
  1100. >>> init()
  1101. >>> A = STDSRelativeTime(table="strds_relative_time",
  1102. ... ident="strds@PERMANENT", start_time=0, end_time=1, unit="years",
  1103. ... granularity=5, map_time="interval")
  1104. >>> A.id
  1105. 'strds@PERMANENT'
  1106. >>> A.start_time
  1107. 0
  1108. >>> A.end_time
  1109. 1
  1110. >>> A.unit
  1111. 'years'
  1112. >>> A.granularity
  1113. 5
  1114. >>> A.map_time
  1115. 'interval'
  1116. >>> A.print_info()
  1117. +-------------------- Relative time -----------------------------------------+
  1118. | Start time:................. 0
  1119. | End time:................... 1
  1120. | Relative time unit:......... years
  1121. | Granularity:................ 5
  1122. | Temporal type of maps:...... interval
  1123. >>> A.print_shell_info()
  1124. start_time='0'
  1125. end_time='1'
  1126. unit=years
  1127. granularity=5
  1128. map_time=interval
  1129. """
  1130. def __init__(
  1131. self,
  1132. table=None,
  1133. ident=None,
  1134. start_time=None,
  1135. end_time=None,
  1136. unit=None,
  1137. granularity=None,
  1138. map_time=None,
  1139. ):
  1140. RelativeTemporalExtent.__init__(self, table, ident, start_time, end_time, unit)
  1141. self.set_granularity(granularity)
  1142. self.set_map_time(map_time)
  1143. def set_granularity(self, granularity):
  1144. """Set the granularity of the space time dataset"""
  1145. self.D["granularity"] = granularity
  1146. def set_map_time(self, map_time):
  1147. """Set the type of the map time
  1148. Registered maps may have different types of time:
  1149. - Single point of time "point"
  1150. - Time intervals "interval"
  1151. - Single point and interval time "mixed"
  1152. This variable will be set automatically when maps are registered.
  1153. """
  1154. self.D["map_time"] = map_time
  1155. def get_granularity(self):
  1156. """Get the granularity of the space time dataset
  1157. :return: None if not found"""
  1158. if "granularity" in self.D:
  1159. return self.D["granularity"]
  1160. else:
  1161. return None
  1162. def get_map_time(self):
  1163. """Get the type of the map time
  1164. Registered maps may have different types of time:
  1165. - Single point of time "point"
  1166. - Time intervals "interval"
  1167. - Single point and interval time "mixed"
  1168. This variable will be set automatically when maps are registered.
  1169. """
  1170. if "map_time" in self.D:
  1171. return self.D["map_time"]
  1172. else:
  1173. return None
  1174. # Properties
  1175. granularity = property(fget=get_granularity, fset=set_granularity)
  1176. map_time = property(fget=get_map_time, fset=set_map_time)
  1177. def print_info(self):
  1178. """Print information about this class in human readable style"""
  1179. RelativeTemporalExtent.print_info(self)
  1180. # 0123456789012345678901234567890
  1181. print(" | Granularity:................ " + str(self.get_granularity()))
  1182. print(" | Temporal type of maps:...... " + str(self.get_map_time()))
  1183. def print_shell_info(self):
  1184. """Print information about this class in shell style"""
  1185. RelativeTemporalExtent.print_shell_info(self)
  1186. print("granularity=" + str(self.get_granularity()))
  1187. print("map_time=" + str(self.get_map_time()))
  1188. ###############################################################################
  1189. class STRDSRelativeTime(STDSRelativeTime):
  1190. def __init__(
  1191. self,
  1192. ident=None,
  1193. start_time=None,
  1194. end_time=None,
  1195. unit=None,
  1196. granularity=None,
  1197. map_time=None,
  1198. ):
  1199. STDSRelativeTime.__init__(
  1200. self,
  1201. "strds_relative_time",
  1202. ident,
  1203. start_time,
  1204. end_time,
  1205. unit,
  1206. granularity,
  1207. map_time,
  1208. )
  1209. class STR3DSRelativeTime(STDSRelativeTime):
  1210. def __init__(
  1211. self,
  1212. ident=None,
  1213. start_time=None,
  1214. end_time=None,
  1215. unit=None,
  1216. granularity=None,
  1217. map_time=None,
  1218. ):
  1219. STDSRelativeTime.__init__(
  1220. self,
  1221. "str3ds_relative_time",
  1222. ident,
  1223. start_time,
  1224. end_time,
  1225. unit,
  1226. granularity,
  1227. map_time,
  1228. )
  1229. class STVDSRelativeTime(STDSRelativeTime):
  1230. def __init__(
  1231. self,
  1232. ident=None,
  1233. start_time=None,
  1234. end_time=None,
  1235. unit=None,
  1236. granularity=None,
  1237. map_time=None,
  1238. ):
  1239. STDSRelativeTime.__init__(
  1240. self,
  1241. "stvds_relative_time",
  1242. ident,
  1243. start_time,
  1244. end_time,
  1245. unit,
  1246. granularity,
  1247. map_time,
  1248. )
  1249. ###############################################################################
  1250. if __name__ == "__main__":
  1251. import doctest
  1252. doctest.testmod()