1/* Part of SWI-Prolog 2 3 Author: Willem Robert van Hage 4 E-mail: W.R.van.Hage@vu.nl 5 WWW: http://www.few.vu.nl/~wrvhage 6 Copyright (c) 2010-2013, Vrije Universiteit Amsterdam 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35/* 36 Internally, all time objects are stored as intervals. 37 point(T) is translated to interval(T,T). 38 If fuzzy time intervals, 39 interval(EarlyBegin,LateBegin,EarlyEnd,LateEnd), 40 should ever be implemented, this could be done by postprocessing 41 over operations on an index containing interval(EarlyBegin,LateEnd). 42 43 Per handle there are two indices, one containing the begin points 44 and the other containing the end points of the intervals. 45 The index containing the end points actually contains negative time 46 points to inverse the order of the index. 47*/ 48 49% TODO: Make version of atom_map that allows double type datums and 50% that has nondet search functions. 51% This would remove the need for the explicit EpochOffset and 52% would speed up all search predicates. 53 54:- module(timeindex, 55 [ time_index/1, % ?Index 56 time_index/4, % +Index, ?BeginIndex, ?EndIndex, ?Epoch 57 time_setting/2, % +Index ?Setting 58 time_setting/1, % ?Setting (uses default index) 59 time_assert/3, % +URI, +Time, +Index 60 time_assert/2, % +URI, +Time (uses default index) 61 time_retract/3, % +URI, +Time, +Index 62 time_retract/2, % +URI, +Time (uses default index) 63 time_clear/2, % +Index, +NewEpochOffset 64 time_clear/1, % +Index 65 time_clear/0, % (uses default index) 66 time_index_all/1, % +Index 67 time_index_all/0, % (uses default index) 68 time_bulkload/2, % :CandidatePred, +Index 69 time_bulkload/1, % :CandidatePred 70 time_intersects/3, % +Time, -URI, +Index 71 time_intersects/2, % (uses default index) 72 time_contains/3, % +Time, -URI, +Index 73 time_contains/2, % (uses default index) 74 time_prev_end/3, % +Time, -URI, +Index 75 time_prev_end/2, % (uses default index) 76 time_next_begin/3, % +Time, -URI, +Index 77 time_next_begin/2, % (uses default index) 78 uri_time/4, % ?URI, ?Time, ?Source, +EpochOffset 79 uri_time/3, % ?URI, ?Time, ?Source (uses offset 0) 80 uri_time/2, % ?URI, ?Time (uses offset 0) 81 parse_timestamp/3, % +TimeStamp, -Epoch, +EpochOffset 82 parse_timestamp/2, % ?TimeStamp, ?Epoch (uses offset 0) 83 84 % Allen's Interval Algebra 85 time_before/2, % +Time, +Time 86 time_after/2, 87 time_meets/2, 88 time_meets_inverse/2, 89 time_overlaps/2, 90 time_overlaps_inverse/2, 91 time_starts/2, 92 time_starts_inverse/2, 93 time_during/2, 94 time_during_inverse/2, 95 time_finishes/2, 96 time_finishes_inverse/2, 97 time_equal/2, 98 99 % Time operations 100 time_expand_before/3, % +Time, +Duration, -Time 101 time_expand_after/3, % +Time, +Duration, -Time 102 time_expand/3, % +Time, +Duration, -Time 103 time_duration/2, % +Time, -Duration 104 time_duration_before/3, % +Time, +Duration, -Time 105 time_duration_after/3, % +Time, +Duration, -Time 106 time_duration/3, % +Time, +Time, -Duration (epoch) 107 time_between/3, % +Time, +Time, -Duration (epoch) 108 109 timestamp_duration/2 % +TimeStamp, -Duration (duration(Y,M,D,H,Min,S)) 110 ]). 111 112:- use_module(library(semweb/rdf_db)). 113:- use_module(library(semweb/rdf_litindex)). 114:- use_module(library(ordsets)). 115:- use_module(library(pairs)). 116 117:- dynamic time_indices/4. 118 119:- rdf_meta time_index(r), 120 time_index(r,?,?,?), 121 time_setting(r,?), 122 time_assert(r,?,r), 123 time_assert(r,?), 124 time_retract(r,?,r), 125 time_retract(r,?), 126 time_clear(r,?), 127 time_clear(r), 128 time_index_all(r), 129 time_bulkload(?,r), 130 time_intersects(?,r,r), 131 time_intersects(?,r), 132 time_contains(?,r,r), 133 time_contains(?,r), 134 time_prev_end(?,r,r), 135 time_prev_end(?,r), 136 time_next_begin(?,r,r), 137 time_next_begin(?,r), 138 uri_time(r,?,t,?), 139 uri_time(r,?,t), 140 uri_time(r,?). 141 142 143time_index(Index) :- time_indices(Index,_,_,_). 144 145time_index(Index, IdxB, IdxE, Epoch) :- 146 time_indices(Index, IdxB, IdxE, Epoch), !. 147time_index(Index, IdxB, IdxE, Epoch) :- 148 nonvar(Epoch), 149 time_new(Index, Epoch), 150 time_indices(Index, IdxB, IdxE, Epoch), !. 151time_index(Index, IdxB, IdxE, Epoch) :- 152 var(Epoch), 153% time_new(Index), 154 time_indices(Index, IdxB, IdxE, Epoch), !.
size(-N)
, N is the number of URI-Time pairs in the index.
epoch(+Epoch)
, sets a new Epoch for the index, clears the index.
epoch(-Epoch)
, Epoch is the current Epoch of the index.164time_setting(Option) :- time_setting(default, Option). 165time_setting(Index, size(N)) :- 166 time_indices(Index,B,_,_), !, 167 rdf_statistics_literal_map(B,size(N,_)). 168time_setting(Index, epoch(E)) :- 169 var(E), 170 time_indices(Index,_,_,E), !. 171time_setting(Index, epoch(E)) :- 172 nonvar(E), 173 format('% Clearing index ~w, setting new Epoch to ~w\n', [Index,E]), 174 time_clear(Index, E).
183time_new(Index) :- time_new(Index, 0). 184time_new(Index, EpochOffset) :- 185 rdf_new_literal_map(B), 186 rdf_new_literal_map(E), 187 assert(time_indices(Index, B, E, EpochOffset)).
195time_assert(URI, T) :- time_assert(URI, T, default). 196time_assert(URI, interval(TB, TE), Index) :- 197 ( time_index(Index) 198 -> true 199 ; time_clear(Index, TB) 200 ), 201 time_index(Index, IdxB, IdxE, EpochOffset), 202 TBE is integer(TB - EpochOffset), 203 TEE is integer(-1 * (TE - EpochOffset)), 204 rdf_insert_literal_map(IdxB, TBE, URI), 205 rdf_insert_literal_map(IdxE, TEE, URI), !. 206time_assert(URI, point(T), Index) :- 207 time_assert(URI, interval(T,T), Index), !. 208time_assert(URI, TimeExpr, Index) :- 209 atom(TimeExpr), 210 parse_timestamp(TimeExpr, T), 211 time_assert(URI, point(T), Index), !. 212time_assert(URI, TimeExpr, Index) :- 213 number(TimeExpr), 214 time_assert(URI, point(TimeExpr), Index), !.
221time_retract(URI, T) :- time_retract(URI, T, default). 222time_retract(URI, interval(TB, TE), Index) :- 223 time_indices(Index, IdxB, IdxE, EpochOffset), 224 TBE is integer(TB - EpochOffset), 225 TEE is integer(-1 * (TE - EpochOffset)), 226 rdf_delete_literal_map(IdxB, TBE, URI), 227 rdf_delete_literal_map(IdxE, TEE, URI).
236time_clear :- time_clear(default). 237time_clear(Index) :- 238 ( time_index(Index, IdxB, IdxE, OldEpochOffset) 239 -> retractall(time_indices(Index, _, _, _)), 240 rdf_destroy_literal_map(IdxB), 241 rdf_destroy_literal_map(IdxE), 242 time_new(Index, OldEpochOffset) 243 ; true 244 ). 245time_clear(Index, NewEpochOffset) :- 246 number(NewEpochOffset), 247 ( time_index(Index, IdxB, IdxE, _OldEpochOffset) 248 -> retractall(time_indices(Index, _, _, _)), 249 rdf_destroy_literal_map(IdxB), 250 rdf_destroy_literal_map(IdxE) 251 ; true 252 ), 253 time_new(Index, NewEpochOffset), !.
261time_index_all :- time_index_all(default). 262time_index_all(Index) :- time_bulkload(uri_time, Index). 263 264:- meta_predicate time_bulkload( ), time_bulkload( , ).
272time_bulkload(CandidatePred) :- time_bulkload(CandidatePred, default). 273time_bulkload(CandidatePred, Index) :- 274 time_clear(Index), 275 forall(call(CandidatePred, URI, Time), 276 time_assert(URI, Time, Index)), 277 time_index(Index,B,_,_), 278 rdf_statistics_literal_map(B,size(K,_)), 279 format('% Added ~w URI-Time pairs to ~w\n',[K,Index]).
interval(Begin,End)
.
NB! The implementation currently does not return intervals that contain the query interval, hence the name time_intersects is currently a misnomer.
292time_intersects(T, URI) :- time_intersects(T, URI, default). 293 294time_intersects(point(T), URI, Index) :- 295 time_intersects(interval(T,T), URI, Index). 296time_intersects(interval(TB, TE), URI, Index) :- 297 time_intersects_impl1(interval(TB, TE), URI, Index). 298% FIXME: buggy implementation, does not find intervals that start 299% before the query interval and end after the query interval. 300% The obvious solution would be to compute the intersection of the 301% set of intervals ending after the begin of the query and the 302% set of intervals starting before the end of the query, but that 303% is a very expensive query. 304% As soon as there is a nondet version of rdf_keys_in_literal_map 305% this implementation could become viable if the hard solutions are 306% delayed until after all easy solutions have been found. 307time_intersects_impl1(interval(TB, TE), URI, Index) :- 308 time_index(Index, IdxB, IdxE, EO), 309 parse_timestamp(TB, TBE, EO), 310 parse_timestamp(TE, TEE, EO), 311 TBI is integer(TBE), 312 TEI is integer(TEE), 313 rdf_keys_in_literal_map(IdxB, between(TBI, TEI), BeginMatch), 314 rdf_litindex:list_to_or(BeginMatch, between(TBI, TEI), BeginOr), 315 rdf_litindex:lookup(BeginOr, IdxB, B2, B3), 316 match_results(B2, B3, B4), 317 TBR is integer(-1 * TBE), 318 TER is integer(-1 * TEE), 319 rdf_keys_in_literal_map(IdxE, between(TER, TBR), EndMatch), 320 rdf_litindex:list_to_or(EndMatch, between(TER, TBR), EndOr), 321 rdf_litindex:lookup(EndOr, IdxE, E2, E3), 322 match_results(E2, E3, E4), 323 append(E4, B4, Matches), 324 % predsort(ord, E4B4, Matches), !, 325 pairs_values(Matches, Values), !, 326 list_to_set(Values, ValueSet), 327 member(URI, ValueSet).
interval(Begin,End)
.335time_contains(T, URI) :- time_contains(T, URI, default). 336time_contains(interval(-,-), URI, Index) :- !, 337 time_contains_all(interval(-,-), URI, Index). 338time_contains(interval(-,End), URI, Index) :- !, 339 time_contains_le(interval(-,End), URI, Index). 340time_contains(interval(Begin,-), URI, Index) :- !, 341 time_contains_ge(interval(Begin,-), URI, Index). 342time_contains(interval(TB, TE), URI, Index) :- 343 time_index(Index, IdxB, IdxE, EO), 344 parse_timestamp(TB, TBE, EO), 345 TBI is integer(TBE), 346 TBR is integer(-1 * TBE), 347 parse_timestamp(TE, TEE, EO), 348 TEI is integer(TEE), 349 TER is integer(-1 * TEE), 350 rdf_keys_in_literal_map(IdxB, between(TBI, TEI), BeginMatch), 351 rdf_litindex:list_to_or(BeginMatch, between(TBI, TEI), BeginOr), 352 rdf_litindex:lookup(BeginOr, IdxB, B2, B3), 353 match_results(B2, B3, B4), 354 rdf_keys_in_literal_map(IdxE, between(TER, TBR), EndMatch), 355 rdf_litindex:list_to_or(EndMatch, between(TER, TBR), EndOr), 356 rdf_litindex:lookup(EndOr, IdxE, E2, E3), 357 match_results(E2, E3, E4), 358 predsort(ord, B4, BS), 359 predsort(rev, E4, ES), 360 pairs_values(BS, BSValues), 361 pairs_values(ES, ESValues), 362 ord_intersection(BSValues, ESValues, Matches), !, 363 member(URI, Matches). 364 365lookup(Index,Key,A,B) :- 366 rdf_litindex:lookup(Key, Index, [A], [B]). 367 368time_contains_all(interval(-,-), URI, Index) :- 369 time_index(Index, IdxB, IdxE, _EO), 370 rdf_keys_in_literal_map(IdxB, all, BeginMatch), 371 rdf_keys_in_literal_map(IdxE, all, EndMatch), 372 maplist(lookup(IdxB),BeginMatch,BM1,BM2), 373 maplist(lookup(IdxB),EndMatch,EM1,EM2), 374 match_results(BM1, BM2, BMatches), 375 match_results(EM1, EM2, EMatches), 376 pairs_values(BMatches, BSValues), 377 pairs_values(EMatches, ESValues), 378 append(BSValues, ESValues, Matches2), 379 list_to_set(Matches2,Matches), !, 380 member(URI, Matches). 381time_contains_le(interval(-, TE), URI, Index) :- 382 time_prev_end(point(TE), URI, Index). 383time_contains_ge(interval(TB, -), URI, Index) :- 384 time_next_begin(point(TB), URI, Index).
393time_prev_end(point(T), URI) :- time_prev_end(interval(T,T), URI, default). 394time_prev_end(interval(T,T1), URI) :- time_prev_end(interval(T,T1), URI, default). 395time_prev_end(point(T), URI, Index) :- time_prev_end(interval(T,T), URI, Index). 396time_prev_end(interval(_,T), URI, Index) :- 397 time_index(Index, _, IdxE, EO), 398 parse_timestamp(T, TE, EO), 399 TER is integer(-1 * TE), 400 rdf_keys_in_literal_map(IdxE, ge(TER), EndMatch), 401 rdf_litindex:list_to_or(EndMatch, ge(TER), EndOr), 402 rdf_litindex:lookup(EndOr, IdxE, E2, E3), 403 match_result(E2, E3, _-URI).
412time_next_begin(point(T), URI) :- time_next_begin(interval(T,T), URI, default). 413time_next_begin(interval(T0,T), URI) :- time_next_begin(interval(T0,T), URI, default). 414time_next_begin(point(T), URI, Index) :- time_next_begin(interval(T,T), URI, Index). 415time_next_begin(interval(T,_), URI, Index) :- 416 time_index(Index, IdxB, _, EO), 417 parse_timestamp(T, TE, EO), 418 TEI is integer(TE), 419 rdf_keys_in_literal_map(IdxB, ge(TEI), BeginMatch), 420 rdf_litindex:list_to_or(BeginMatch, ge(TEI), BeginOr), 421 rdf_litindex:lookup(BeginOr, IdxB, B2, B3), 422 match_result(B2, B3, _-URI). 423 424zip_tree_member([H0|T0], [H1|T1], R) :- 425 is_list(H0), 426 ( zip_tree_member(H0, H1, R) 427 ; zip_tree_member(T0, T1, R) 428 ). 429zip_tree_member([[H0]], [H1|T1], R) :- 430 ( member(H, H1), 431 R = H0-H 432 ; zip_tree_member([H0], T1, R) 433 ). 434 435zip_tree(_, [], []). 436zip_tree(A, B, A-B) :- \+is_list(A). 437zip_tree([], [B], nil-B). 438zip_tree([H0], [H1|T1], [H|T]) :- 439 \+is_list(H0), 440 zip_tree(H0, H1, H), 441 zip_tree([H0], T1, T). 442zip_tree([H0|T0], [H1|T1], [H|T]) :- 443 zip_tree(H0, H1, H), 444 zip_tree(T0, T1, T). 445 446match_results(A, B, C) :- 447 zip_tree(A, B, Z), 448 flatten(Z, C). 449match_result(A, B, C) :- 450 zip_tree_member(A, B, C). 451 452ord(>, between(_,_,A)-_, between(_,_,B)-_) :- A > B. 453ord(<, between(_,_,A)-_, between(_,_,B)-_) :- A < B. 454ord(>, le(_,A)-_, le(_,B)-_) :- A > B. 455ord(<, le(_,A)-_, le(_,B)-_) :- A < B. 456ord(=, _, _). 457rev(>, between(_,_,A)-_, between(_,_,B)-_) :- A < B. 458rev(<, between(_,_,A)-_, between(_,_,B)-_) :- A > B. 459rev(>, le(_,A)-_, le(_,B)-_) :- A < B. 460rev(>, le(_,A)-_, le(_,B)-_) :- A > B. 461rev(=, _, _).
472uri_time(URI, interval(Begin, End)) :- uri_time(URI, interval(Begin, End), _Source, 0). 473uri_time(URI, interval(Begin, End), Source) :- uri_time(URI, interval(Begin, End), Source, 0). 474uri_time(URI, interval(Begin, End), Source, EpochOffset) :- 475 time_candidate(URI, interval(TB,TE), Source), 476 parse_timestamp(TB, Begin0), 477 parse_timestamp(TE, End0), 478 Begin is Begin0 - EpochOffset, 479 End is End0 - EpochOffset. 480 481:- rdf_register_ns(sem, 'http://semanticweb.cs.vu.nl/2009/11/sem/'). 482:- rdf_register_ns(owltime, 'http://www.w3.org/2006/time#'). 483 484time_candidate(URI, TimeStamp) :- time_candidate(URI, TimeStamp, _Source). 485time_candidate(URI, TimeStamp, Source) :- 486 owl_time_xsd_candidate(URI, TimeStamp, Source). 487time_candidate(URI, TimeStamp, Source) :- 488 sem_time_candidate(URI, TimeStamp, Source). 489 490sem_time_candidate(URI, TimeStamp) :- sem_time_candidate(URI, TimeStamp, _Source). 491sem_time_candidate(URI, interval(Begin,End), Source) :- 492 nonvar(Source), 493 ( rdf(URI, sem:hasBeginTimeStamp, literal(TB), Source) 494 -> ( TB = type(_,Begin) 495 -> true 496 ; Begin = TB 497 ) 498 ; Begin = - 499 ), 500 ( rdf(URI, sem:hasEndTimeStamp, literal(TE), Source) 501 -> ( TE = type(_,End) 502 -> true 503 ; End = TE 504 ) 505 ; End = - 506 ), 507 ( Begin = -, End = - 508 -> fail 509 ; true 510 ). 511sem_time_candidate(URI, interval(Begin,End), Source) :- 512 var(Source), 513 ( rdf(URI, sem:hasBeginTimeStamp, literal(TB), Source1) 514 -> ( TB = type(_,Begin) 515 -> true 516 ; Begin = TB 517 ) 518 ; Begin = - 519 ), 520 ( Source1 = Source:_ 521 -> true 522 ; Source = Source1 523 ), 524 ( rdf(URI, sem:hasEndTimeStamp, literal(TE), Source) 525 -> ( TE = type(_,End) 526 -> true 527 ; End = TE 528 ) 529 ; End = - 530 ), 531 ( Begin = -, End = - 532 -> fail 533 ; true 534 ). 535 536sem_time_candidate(URI, interval(TimeStamp,TimeStamp), Source) :- 537 rdf(URI, sem:hasTimeStamp, literal(L), Source), 538 ( L = type(_,TimeStamp) 539 -> true 540 ; L = TimeStamp 541 ). 542 543owl_time_xsd_candidate(URI, interval(TimeStamp,TimeStamp), Source) :- 544 rdf(URI, owltime:inXSDDateTime, literal(L), Source), 545 ( L = type(_,TimeStamp) 546 -> true 547 ; L = TimeStamp 548 ).
557parse_timestamp(TimeStamp, Epoch) :- 558 var(TimeStamp), 559 number(Epoch), 560 stamp_date_time(Epoch, Date, 'UTC'), 561 format_time(atom(TimeStamp), '%FT%TZ', Date), !. 562parse_timestamp(TimeStamp, Epoch) :- parse_timestamp(TimeStamp, Epoch, 0).
571parse_timestamp(TimeStamp, Epoch, EpochOffset) :- 572 nonvar(TimeStamp), 573 ( number(TimeStamp) 574 -> E = TimeStamp 575 ; atom(TimeStamp), iso_timestamp_epoch(TimeStamp, E), ! 576 ; atom(TimeStamp), sic_timestamp_epoch(TimeStamp, E), ! 577 ; \+atom(TimeStamp), timex_timestamp_epoch(TimeStamp, E), ! 578 % extend here 579 ), 580 Epoch is E - EpochOffset. 581 582 583iso_timestamp_epoch(TimeStamp, T) :- 584 parse_time(TimeStamp, T). 585 586sic_timestamp_epoch(TimeStamp, T) :- 587 atom_number(TimeStamp, T). 588 589timex_timestamp_epoch(type(Type,TimeStamp), T) :- 590 rdf_equal(Type, rdf:'XMLLiteral'), 591 xml_timestamp(TimeStamp, T). 592 593xml_timestamp(TimeStamp, T) :- 594 ( xpath(TimeStamp, //(timex2), element(_,Attr,_)) % plain XML timex2 tag 595 -> true 596 ; xpath(TimeStamp, //(_:timex2), element(_,Attr,_)) % timex2 in some namespace 597 ), !, 598 memberchk('VAL'=ISO, Attr), 599 parse_time(ISO, T). % Doesn't deal with local time 600xml_timestamp(TimeStamp, T) :- 601 ( xpath(TimeStamp, //(timex3), element(_,Attr,_)) % plain XML timex3 tag 602 -> true 603 ; xpath(TimeStamp, //(_:timex3), element(_,Attr,_)) % timex3 in some namespace 604 ), !, 605 memberchk(value=ISO, Attr), 606 parse_time(ISO, T). % Doesn't deal with local time 607 608 609/* 610 * Allen's interval algebra 611 */ 612 613% assumes point(T) is equal to interval(T,T) 614 615time_to_interval(interval(T1,T2), interval(T1,T2)) :- 616 number(T1), number(T2), !. 617time_to_interval(point(T), interval(T,T)) :- 618 number(T), !. 619time_to_interval(interval(T1,T2), interval(T3,T4)) :- 620 parse_timestamp(T1,T3), 621 parse_timestamp(T2,T4), !. 622time_to_interval(point(T1), interval(T2,T2)) :- 623 parse_timestamp(T1,T2), !. 624time_to_interval(T1, interval(T2,T2)) :- 625 parse_timestamp(T1,T2), !. 626 627 628time_overlaps(Ta, Tb) :- 629 time_to_interval(Ta,interval(T1,T2)), 630 time_to_interval(Tb,interval(T3,T4)), 631 T1 =< T4, 632 T2 >= T3. 633 634time_overlaps_inverse(T1,T2) :- time_overlaps(T2,T1). 635 636time_during(Ta, Tb) :- 637 time_to_interval(Ta, interval(T1,T2)), 638 time_to_interval(Tb, interval(T3,T4)), 639 T1 =< T3, 640 T2 >= T4. 641 642time_during_inverse(T1,T2) :- time_during(T2,T1). 643 644time_before(Ta, Tb) :- 645 time_to_interval(Ta, interval(_,T1)), 646 time_to_interval(Tb, interval(T2,_)), 647 T1 < T2. 648 649time_after(T1,T2) :- time_before(T2,T1). 650 651time_meets(Ta, Tb) :- 652 time_to_interval(Ta, interval(_,T)), 653 time_to_interval(Tb, interval(T,_)). 654 655time_meets_inverse(T1,T2) :- time_meets_inverse(T2,T1). 656 657time_starts(Ta, Tb) :- 658 time_to_interval(Ta, interval(T,T1)), 659 time_to_interval(Tb, interval(T,T2)), 660 T1 =< T2. 661 662time_starts_inverse(T1,T2) :- time_starts(T2,T1). 663 664time_finishes(Ta, Tb) :- 665 time_to_interval(Ta, interval(T1,T)), 666 time_to_interval(Tb, interval(T2,T)), 667 T1 >= T2. 668 669time_finishes_inverse(T1,T2) :- time_finishes(T2,T1). 670 671time_equal(T,T) :- time_to_interval(T,_). 672 673 674/* 675 * Operations on Time points and intervals 676 */ 677 678time_expand_before(T, Margin, interval(T1,Tb)) :- 679 time_to_interval(T, interval(Ta,Tb)), 680 T1 is Ta - Margin. 681 682time_expand_after(T, Margin, interval(Ta,T1)) :- 683 time_to_interval(T, interval(Ta,Tb)), 684 T1 is Tb + Margin. 685 686time_expand(T, Margin, interval(T1,T2)) :- 687 time_to_interval(T, interval(Ta,Tb)), 688 T1 is Ta - Margin, 689 T2 is Tb + Margin. 690 691time_duration(T, D) :- 692 time_to_interval(T, interval(Ta,Tb)), 693 D is Tb - Ta. 694 695time_duration_before(T, D, point(T2)) :- 696 time_to_interval(T,interval(T1,_)), 697 T2 is T1 - D. 698 699time_duration_after(T, D, point(T2)) :- 700 time_to_interval(T,interval(_,T1)), 701 T2 is T1 + D. 702 703time_duration(Ta, Tb, D) :- 704 time_to_interval(Ta, interval(T0,T1)), 705 time_to_interval(Tb, interval(T2,T3)), 706 ( time_before(interval(T0,T1), interval(T2,T3)) 707 -> time_duration(interval(T0,T3), D) 708 ; time_duration(interval(T2,T1), D0), 709 D is -1 * D0 710 ). 711 712time_between(Ta, Tb, D) :- 713 time_to_interval(Ta, interval(T0,T1)), 714 time_to_interval(Tb, interval(T2,T3)), 715 ( time_before(interval(T0,T1), interval(T2,T3)) 716 -> time_duration(interval(T1,T2), D) 717 ; time_duration(interval(T3,T0), D0), 718 D is -1 * D0 719 ). 720 721timestamp_duration(TimeStamp, duration(Years,Months,Days,Hours,Minutes,Seconds)) :- 722 abs(TimeStamp,T), 723% sign(TimeStamp,Sign), 724 stamp_date_time(0, date(Y0,M0,D0,H0,Mi0,S0,_,_,_), 0), 725 stamp_date_time(T, date(Y1,M1,D1,H1,Mi1,S1,_,_,_), 0), 726 Years is Y1 - Y0, 727 Months is M1 - M0, 728 Days is D1 - D0, 729 Hours is H1 - H0, 730 Minutes is Mi1 - Mi0, 731 Seconds is S1 - S0. 732 733parse_duration(ISO, duration(Y,M,D,H,Mi,S)) :- 734 phrase(duration(Y,M,D,H,Mi,S),Ts), 735 atom_codes(ISO,Ts), !. 736 737 738% does not follow the entire ISO 8601 spec yet 739duration(Y,M,D,H,Mi,S) --> 740 { nonvar(Y), 741 number_codes(Y,Yc), 742 number_codes(M,Mc), 743 number_codes(D,Dc), 744 number_codes(H,Hc), 745 number_codes(Mi,Mic), 746 number_codes(S,Sc) 747 }, 748 "P", , "Y", , "M", , "D", "T", , "H", , "M", , "S". 749 750duration(Y,M,D,H,Mi,S) --> 751 { var(Y) }, 752 "P", , "Y", , "M", , "D", "T", , "H", , "M", , "S", 753 { 754 number_codes(Y,Yc), 755 number_codes(M,Mc), 756 number_codes(D,Dc), 757 number_codes(H,Hc), 758 number_codes(Mi,Mic), 759 number_codes(S,Sc) 760 }