| (Interval)

The interval type in Rax represents a duration starting at a given point in time and ending at a given point in time. For example, "yesterday" or "today, from 9am to 5pm." The time-interval type is denoted by the | symbol in Rax. The ISO 8601 strings for intervals are somewhat more complex but still logical extensions of the ones mentioned above. Also time, absolute and relative values can be grouped (using [ and ]) and cast to interval using (|) like so:

    |: over_5_weeks := (|)"2013-07-12T03:44/2013-08-22T12:32";
    |: twenty_four_ := (|)[(@)"now",(^)"P1D"];
         

A tuple needs to be of one of the following types to be cast to an interval: [@:begin, @:end], [@:begin, ^:duration], [@:begin, ~:duration], [^:duration, @:end], [~:duration, @:end]. The cast to an interval from a tuple, is straightforward but can look intimidating, especially when the tuple is populated with casted strings itself. Therefore Rax has an create interval operator | ..., ... | that takes two arguments that can be either a literal string, time, absolute or relative. Note that string arguments do not need to be cast to a temporal type. If it starts with a "P" it is taken to be a relative duration. This makes the two definitions below equivalent.

    |: twenty_four2 := (|)[(@)"now",(^)"P1D"];
    |: twenty_four3 := |"now","P1D"|;
         

Obviously intervals cannot be added or multiplied. However, using the <: (element of) and :> (contains) operators, it is possible to check if a given point in time falls within an interval. For example:

    |: some_week := (|)"2011-10-18T00:00:00/P1W";
    `print (@)"2011-10-21" <: some_week;       // Output: true
    `print some_week :> (@)"2014-10-21";       // Output: false
       

Note that the begin point of an interval falls within this interval, while the end point doesn't, which is illustrated by the following code snippet:

    @:begin    := (@)"now";
    @:end      := begin + (^)"PT1H";
    |:interval := (|)[begin, end];
    `print begin <: interval;                  // Output: true
    `print end   <: interval;                  // Output: false
       

The following table summarizes the operators defined on |.

Table 4.4. Operators defined on |

SyntaxExplanation
i1 := i2Assignment
i1 == i2Equals
i1 != i2Not equals
t <: iElement of, i is of type |. Returns true, if the point in time t is an element of the interval i. For example: (@)"2014-09-13" <: (|)"2014-09-11/P1W" is true.
i :> tContains, i is of type |. Returns true, if the interval i contains the point in time t. For example: (|)"2014-09-11/P1W" :> (@)"2014-09-13".
i << d Left shift, i is of type |, d is of type ^ or ~. Returns the interval value where a duration of d has been subtracted from both the begin and the end of the interval. The interval i has been shifted back in time by a duration of d. For example: (|)"2014-09-11/P1W" << (^)"P1D".
i >> d Right shift, i is of type |, d is of type ^ or ~. Returns the interval value where a duration of d has been added to both the begin and the end of the interval. The interval i has been shifted forward in time by a duration of d. For example: (|)"2014-09-11/P1W" >> (^)"P1D".


There are also many useful operators defined on sets of tuples containing intervals, such as @&@ (temporal and) which we've already met in Chapter 2, Getting started. For example, to compute an overlap of two intervals:

    |: a_week       := (|)"2011-10-18T00:00:00/P1W";
    |: another_week := (|)"2011-10-17T00:00:00/P1W";
    {|}: overlap    := {[a_week]} @&@ {[another_week]};
    `print overlap;

    // Output: {2011-10-18T00:00:00/2011-10-24T00:00:00}
       

Such temporal operators enable intuitive and succinct code for temporal data manipulation. In Chapter 8, Ordered sets, the section called “Temporal relational operators”, we will meet more of these operators.