{"id":16577800,"url":"https://github.com/philippus/between","last_synced_at":"2025-10-29T05:30:31.129Z","repository":{"id":29580728,"uuid":"121162346","full_name":"Philippus/between","owner":"Philippus","description":"↔️ (temporal) intervals and their relations","archived":false,"fork":false,"pushed_at":"2025-01-25T10:19:30.000Z","size":420,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-01T22:23:17.091Z","etag":null,"topics":["intervals","scala","time"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Philippus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["Philippus"]}},"created_at":"2018-02-11T20:07:56.000Z","updated_at":"2025-01-25T10:19:34.000Z","dependencies_parsed_at":"2023-02-14T11:31:07.240Z","dependency_job_id":"6f711e39-ca61-4b42-86e4-d94053e8a821","html_url":"https://github.com/Philippus/between","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Philippus%2Fbetween","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Philippus%2Fbetween/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Philippus%2Fbetween/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Philippus%2Fbetween/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Philippus","download_url":"https://codeload.github.com/Philippus/between/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238776928,"owners_count":19528809,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["intervals","scala","time"],"created_at":"2024-10-11T22:12:18.113Z","updated_at":"2025-10-29T05:30:25.771Z","avatar_url":"https://github.com/Philippus.png","language":"Scala","funding_links":["https://github.com/sponsors/Philippus"],"categories":[],"sub_categories":[],"readme":"# Between\n\n[![build](https://github.com/Philippus/between/workflows/build/badge.svg)](https://github.com/Philippus/between/actions/workflows/scala.yml?query=workflow%3Abuild+branch%3Amain)\n[![codecov](https://codecov.io/gh/Philippus/between/branch/main/graph/badge.svg)](https://codecov.io/gh/Philippus/between)\n![Current Version](https://img.shields.io/badge/version-0.6.0-brightgreen.svg?style=flat \"0.6.0\")\n[![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org)\n[![license](https://img.shields.io/badge/license-MPL%202.0-blue.svg?style=flat \"MPL 2.0\")](LICENSE)\n\nBetween is a library for working with (time) intervals and the relations between them. It takes as a basis the thirteen\nrelations of Allen's Interval Algebra. This is a system for reasoning about (temporal) intervals as described in\nthe paper [Maintaining Knowledge about Temporal Intervals](https://cse.unl.edu/~choueiry/Documents/Allen-CACM1983.pdf).\n\n## Installation\nBetween is published for Scala 2.13 and Scala 3. To start using it add the following to your `build.sbt`:\n\n```\nlibraryDependencies += \"nl.gn0s1s\" %% \"between\" % \"0.6.0\"\n```\n\n## Example usage\nWhen the endpoints of an interval are known, the `Interval[T]` case class is available for testing all possible\n[relations](#relations) between intervals. It needs two values `-` and `+` of type `T` which reflect the (inclusive)\nendpoints of an interval. For the type `T` there needs to be an implicit `Ordering` trait available. Additionally the\nendpoint `-` needs to be smaller than the endpoint `+`.\n\nThe example below shows two examples for `Double` and `java.time.Instant`:\n\n```scala\nimport nl.gn0s1s.between._\n\nval i = Interval[Int](1, 2) // i: nl.gn0s1s.between.Interval[Int] = Interval(1,2)\nval j = Interval[Int](2, 3) // j: nl.gn0s1s.between.Interval[Int] = Interval(2,3)\n\ni meets j // res0: Boolean = true\nj metBy i // res1: Boolean = true\n\nval k = Interval[java.time.Instant](java.time.Instant.ofEpochSecond(1000L), java.time.Instant.ofEpochSecond(2000L))\n// k: nl.gn0s1s.between.Interval[java.time.Instant] = Interval(1970-01-01T00:16:40Z,1970-01-01T00:33:20Z)\n\nval l = Interval[java.time.Instant](java.time.Instant.ofEpochSecond(1500L), java.time.Instant.ofEpochSecond(2500L))\n// l: nl.gn0s1s.between.Interval[java.time.Instant] = Interval(1970-01-01T00:25:00Z,1970-01-01T00:41:40Z)\n\nk overlaps l // res2: Boolean = true\nl overlappedBy k // res3: Boolean = true\n```\n\n### Relations\n\nGiven two intervals there is always only one of the following thirteen defined relations true:\n\n| relation       | symbol  | inverse | inverse relation   | diagram                     |\n| -------------- | ------- | ------- | ------------------ | --------------------------- |\n| x `before` y   |   `\u003c`   |   `\u003e`   | y `after` x        | \u003cpre\u003exxx yyy\u003c/pre\u003e          |\n| x `equals` y   |   `==`  |  `==`   | y `equals` x       | \u003cpre\u003e  xxx\u003cbr\u003e  yyy\u003c/pre\u003e   |\n| x `meets` y    |   `m`   |  `mi`   | y `metBy` x        | \u003cpre\u003exxxyyy\u003c/pre\u003e           |\n| x `overlaps` y |   `o`   |  `oi`   | y `overlappedBy` x | \u003cpre\u003e xxx\u003cbr\u003e  yyy\u003c/pre\u003e    |\n| x `during` y   |   `d`   |  `di`   | y `contains` x     | \u003cpre\u003e  xxx \u003cbr\u003e yyyyy\u003c/pre\u003e |\n| x `starts` y   |   `s`   |  `si`   | y `startedBy` x    | \u003cpre\u003e xxx \u003cbr\u003e yyyyy\u003c/pre\u003e  |\n| x `finishes` y |   `f`   |  `fi`   | y `finishedBy` x   | \u003cpre\u003e   xxx\u003cbr\u003e yyyyy\u003c/pre\u003e |\n\n* `before` and `after` are also available as `precedes` and `precededBy`, respectively.\n* `finishes` and `finishedBy` are also available as `ends` and `endedBy`.\n\nThere's a `findRelation` method which can be used to find out which relation exists between two intervals. The\n`Relation` has an `inverse` method implemented, which gives the inverse of a relation.\n\n```scala\nimport nl.gn0s1s.between._\n\nval i = Interval[Int](1, 2) // i: nl.gn0s1s.between.Interval[Int] = Interval(1,2)\nval j = Interval[Int](2, 3) // j: nl.gn0s1s.between.Interval[Int] = Interval(2,3)\n\nval relationBetweenIAndJ = i.findRelation(j) // relationBetweenIAndJ: nl.gn0s1s.between.Relation = m\n\nrelationBetweenIAndJ.inverse // res0: nl.gn0s1s.between.Relation = mi\n```\n\n### Additional methods\nA number of additional methods are availabe on the `Interval[T]` case class, some of which may be familiar for users of\nthe [ThreeTen-Extra](https://www.threeten.org/threeten-extra/apidocs/org.threeten.extra/org/threeten/extra/Interval.html) Interval class.\n\n* `abuts`, checks if the interval abuts the supplied interval\n* `encloses`, checks if the interval encloses the supplied interval\n* `enclosedBy`, checks if the interval is enclosed by the supplied interval\n* `gap`, returns the interval that is between this interval and the supplied interval\n* `intersection`, returns the intersection of this interval and the supplied interval\n* `minus`, returns the result of subtracting the supplied interval from this interval\n* `span`, returns the smallest interval that contains this interval and the supplied interval\n* `union`, returns the union of this interval and the supplied interval\n\nSome point related methods are:\n* `after`, checks if the interval is after the supplied point\n* `before`, checks if the interval is before the supplied point\n* `chop`, chops this interval into two intervals that meet at the supplied point\n* `clamp`, clamps a supplied point within the interval\n* `contains`, checks if supplied point is within the interval\n* `endsAt`, checks if the interval ends at the supplied point\n* `startsAt`, checks if the interval starts at the supplied point\n* `with-`, returns a copy of this interval with the supplied `-` endpoint\n* `with+`, returns a copy of this interval with the supplied `+` endpoint\n\n### Reasoning\nI got inspired to write this library `during` [Eric Evans](https://github.com/ericevans0)' talk at the\n[Domain-Driven Design Europe 2018](https://dddeurope.com/2018/) conference. I started writing it in the train on my way\nback from the conference, this can be represented like this:\n\n`write lib \u003c-(o)- - train - -(\u003e, mi)-\u003e DDD Europe - -(di)-\u003e EE talk \u003c-(d) - - inspired`\n\nSince the composition table of relations and the `constraints` method are implemented we can find out what the possible\nrelations between `write lib` and `DDD Europe` are:\n\n```scala\nimport nl.gn0s1s.between._\n\nRelation.constraints(Set(o), Set(\u003c, m)) // res0: Set[nl.gn0s1s.between.Relation] = Set(\u003c)\n```\n\n## Resources\nAllen's Interval Algebra:\n- [Maintaining Knowledge about Temporal Intervals](https://cse.unl.edu/~choueiry/Documents/Allen-CACM1983.pdf)\n- [Wikipedia entry](https://en.wikipedia.org/wiki/Allen%27s_interval_algebra)\n- Thomas A. Alspaugh's Foundations Material on [Allen's Interval Algebra](https://thomasalspaugh.org/pub/fnd/allen.html)\n- [Moments and Points in an Interval-Based Temporal Logic](https://onlinelibrary.wiley.com/doi/10.1111/j.1467-8640.1989.tb00329.x)\n\nRelated links:\n- [A Modal Logic for Chopping Intervals](https://staff.fnwi.uva.nl/y.venema/papers/1991/vene-moda91.pdf)\n- [SOWL QL: Querying Spatio - Temporal Ontologies in OWL](http://www.intelligence.tuc.gr/~petrakis/publications/SOWLQL-JDS.pdf)\n- [AsterixDB Temporal Functions: Allen’s Relations](https://asterixdb.apache.org/docs/0.8.8-incubating/aql/allens.html)\n- Haskell package that does something similar for Haskell - https://github.com/novisci/interval-algebra\n\n## License\nThe code is available under the [Mozilla Public License, version 2.0](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphilippus%2Fbetween","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphilippus%2Fbetween","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphilippus%2Fbetween/lists"}