Between is a library for working with (time) intervals and the relations between them. It takes as a basis the thirteen relations of Allen's Interval Algebra. This is a system for reasoning about (temporal) intervals as described in the paper Maintaining Knowledge about Temporal Intervals.

Between is published for Scala 2.13. To start using it add the following to your `build.sbt`

:

```
libraryDependencies += "nl.gn0s1s" %% "between" % "0.5.0"
```

When the endpoints of an interval are known, the `Interval[T]`

case class is available for testing all possible
relations between intervals. It needs two values `-`

and `+`

of type `T`

which reflect the (inclusive)
endpoints of an interval. For the type `T`

there needs to be an implicit `Ordering`

trait available. Additionally the
endpoint `-`

needs to be smaller than the endpoint `+`

.

The example below shows two examples for `Double`

and `java.time.Instant`

:

```
import nl.gn0s1s.between._
val i = Interval[Int](1, 2) // i: nl.gn0s1s.between.Interval[Int] = Interval(1,2)
val j = Interval[Int](2, 3) // j: nl.gn0s1s.between.Interval[Int] = Interval(2,3)
i meets j // res0: Boolean = true
j metBy i // res1: Boolean = true
val k = Interval[java.time.Instant](java.time.Instant.ofEpochSecond(1000L), java.time.Instant.ofEpochSecond(2000L))
// k: nl.gn0s1s.between.Interval[java.time.Instant] = Interval(1970-01-01T00:16:40Z,1970-01-01T00:33:20Z)
val l = Interval[java.time.Instant](java.time.Instant.ofEpochSecond(1500L), java.time.Instant.ofEpochSecond(2500L))
// l: nl.gn0s1s.between.Interval[java.time.Instant] = Interval(1970-01-01T00:25:00Z,1970-01-01T00:41:40Z)
k overlaps l // res2: Boolean = true
l overlappedBy k // res3: Boolean = true
```

Given two intervals there is always only one of the following thirteen defined relations true:

relation | symbol | inverse | inverse relation | diagram |
---|---|---|---|---|

x `before` y |
`<` |
`>` |
y `after` x |
xxx yyy |

x `equals` y |
`==` |
`==` |
y `equals` x |
xxx |

x `meets` y |
`m` |
`mi` |
y `metBy` x |
xxxyyy |

x `overlaps` y |
`o` |
`oi` |
y `overlappedBy` x |
xxx |

x `during` y |
`d` |
`di` |
y `contains` x |
xxx |

x `starts` y |
`s` |
`si` |
y `startedBy` x |
xxx |

x `finishes` y |
`f` |
`fi` |
y `finishedBy` x |
xxx |

`before`

and`after`

are also available as`precedes`

and`precededBy`

, respectively.`finishes`

and`finishedBy`

are also available as`ends`

and`endedBy`

.

There's a `findRelation`

method which can be used to find out which relation exists between two intervals. The
`Relation`

has an `inverse`

method implemented, which gives the inverse of a relation.

```
import nl.gn0s1s.between._
val i = Interval[Int](1, 2) // i: nl.gn0s1s.between.Interval[Int] = Interval(1,2)
val j = Interval[Int](2, 3) // j: nl.gn0s1s.between.Interval[Int] = Interval(2,3)
val relationBetweenIAndJ = i.findRelation(j) // relationBetweenIAndJ: nl.gn0s1s.between.Relation = m
relationBetweenIAndJ.inverse // res0: nl.gn0s1s.between.Relation = mi
```

A number of additional methods are availabe on the `Interval[T]`

case class, some of which may be familiar for users of
the ThreeTen-Extra Interval class.

`abuts`

, checks if the interval abuts the supplied interval`encloses`

, checks if the interval encloses the supplied interval`enclosedBy`

, checks if the interval is enclosed by the supplied interval`gap`

, returns the interval that is between this interval and the supplied interval`intersection`

, returns the intersection of this interval and the supplied interval`minus`

, returns the result of subtracting the supplied interval from this interval`span`

, returns the smallest interval that contains this interval and the supplied interval`union`

, returns the union of this interval and the supplied interval

Some point related methods are:

`after`

, checks if the interval is after the supplied point`before`

, checks if the interval is before the supplied point`chop`

, chops this interval into two intervals that meet at the supplied point`clamp`

, clamps a supplied point within the interval`contains`

, checks if supplied point is within the interval`endsAt`

, checks if the interval ends at the supplied point`startsAt`

, checks if the interval starts at the supplied point`with-`

, returns a copy of this interval with the supplied`-`

endpoint`with+`

, returns a copy of this interval with the supplied`+`

endpoint

I got inspired to write this library `during`

Eric Evans' talk at the
Domain-Driven Design Europe 2018 conference. I started writing it in the train on my way
back from the conference, this can be represented like this:

`write lib <-(o)- - train - -(>, mi)-> DDD Europe - -(di)-> EE talk <-(d) - - inspired`

Since the composition table of relations and the `constraints`

method are implemented we can find out what the possible
relations between `write lib`

and `DDD Europe`

are:

```
import nl.gn0s1s.between._
Relation.constraints(Set(o), Set(<, m)) // res0: Set[nl.gn0s1s.between.Relation] = Set(<)
```

Allen's Interval Algebra:

- Maintaining Knowledge about Temporal Intervals
- Wikipedia entry
- Thomas A. Alspaugh's Foundations Material on Allen's Interval Algebra
- Moments and Points in an Interval-Based Temporal Logic

Related links:

- A Modal Logic for Chopping Intervals
- SOWL QL: Querying Spatio - Temporal Ontologies in OWL
- AsterixDB Temporal Functions: Allen’s Relations
- Haskell package that does something similar for Haskell - https://github.com/novisci/interval-algebra

The code is available under the Mozilla Public License, version 2.0.