gob/datetime/range.go

159 lines
4.3 KiB
Go
Raw Normal View History

2023-10-31 10:18:00 +00:00
package datetime
import (
. "gitea.zaclys.com/bvaudour/gob/option"
)
2023-11-03 19:33:26 +00:00
// TimeComparator représente tout type dindication de temps.
type TimeComparator[E any] interface {
Eq(E) bool
Ne(E) bool
Gt(E) bool
Ge(E) bool
Lt(E) bool
Le(E) bool
IsNow() bool
IsPast() bool
IsFuture() bool
Now() E
2023-10-31 10:18:00 +00:00
}
2023-11-03 19:33:26 +00:00
// Min retourne le temps le plus petit.
func Min[C TimeComparator[C]](e C, args ...C) C {
out := e
for _, a := range args {
if a.Lt(out) {
out = a
}
2023-10-31 10:18:00 +00:00
}
2023-11-03 19:33:26 +00:00
return out
}
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// Max retourne le temps le plus grand.
func Max[C TimeComparator[C]](e C, args ...C) C {
out := e
for _, a := range args {
if a.Gt(out) {
out = a
}
2023-10-31 10:18:00 +00:00
}
2023-11-03 19:33:26 +00:00
return out
2023-10-31 10:18:00 +00:00
}
2023-11-03 19:33:26 +00:00
// Range représente une période entre deux bornes temporelles.
type Range[C TimeComparator[C]] struct {
begin, end C
}
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// NewRange retourne une période entre begin et end.
// Si begin < end, les bornes sont inversées.
func NewRange[C TimeComparator[C]](begin, end C) Range[C] {
if begin.Gt(end) {
begin, end = end, begin
}
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
return Range[C]{begin, end}
}
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// Begin retourne le début de la période.
func (r Range[C]) Begin() C { return r.begin }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// End retourne la fin de la période.
func (r Range[C]) End() C { return r.end }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// Before retourne vrai si e est située avant la période.
func (r Range[C]) Before(e C) bool { return e.Lt(r.begin) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// After retourne vrai si e est située après la période.
func (r Range[C]) After(e C) bool { return e.Gt(r.end) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// Contains retourne vrai si e ∈ [begin;end].
func (r Range[C]) Contains(e C) bool { return e.Ge(r.begin) && e.Le(r.end) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// ContainsStrictLeft retourne vrai si e ∈ ]begin;end].
func (r Range[C]) ContainsStrictLeft(e C) bool { return e.Gt(r.begin) && e.Le(r.end) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// ContainsStrictRight retourne vrai si e ∈ [begin;end[.
func (r Range[C]) ContainsStrictRight(e C) bool { return e.Ge(r.begin) && e.Lt(r.end) }
// ContainsStrict retourne vrai si e ∈ ]begin;end[.
func (r Range[C]) ContainsStrict(e C) bool { return e.Gt(r.begin) && e.Lt(r.end) }
2023-10-31 10:18:00 +00:00
// IsNow retourne vrai si la période est en cours.
2023-11-03 19:33:26 +00:00
func (r Range[C]) IsNow() bool { return r.Contains(r.begin.Now()) }
// IsPast retourne vrai si la période est située dans le passé.
func (r Range[C]) IsPast() bool { return r.Before(r.begin.Now()) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// IsFuture retourne vrai la période est située dans le futur.
func (r Range[C]) IsFuture() bool { return r.After(r.begin.Now()) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// BeforeRange retourne vrai si r1 est terminée avant que r2 commence.
func (r1 Range[C]) BeforeRange(r2 Range[C]) bool { return r1.end.Le(r2.begin) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// AfterRange retourne vrai si r2 est terminée avec que r1 commence.
func (r1 Range[C]) AfterRange(r2 Range[C]) bool { return r2.BeforeRange(r1) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// ContainsRange retourne vrai si r2 est intégralement comprise dans r1.
func (r1 Range[C]) ContainsRange(r2 Range[C]) bool {
return r1.begin.Le(r2.begin) && r1.end.Ge(r2.end)
}
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// InRange retourne vrai si r2 comprend intégralement r1.
func (r1 Range[C]) InRange(r2 Range[C]) bool { return r2.ContainsRange(r1) }
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// Excludes retourne vrai si r1 et r2 ne se chevauchent pas.
func (r1 Range[C]) Excludes(r2 Range[C]) bool {
return r1.end.Le(r2.begin) || r1.begin.Ge(r2.end)
}
// Overlaps retourne vrai si r1 et r2 se chevauchent.
func (r1 Range[C]) Overlaps(r2 Range[C]) bool {
return r1.begin.Lt(r2.end) && r1.end.Gt(r2.begin)
}
2023-10-31 10:18:00 +00:00
2023-11-03 19:33:26 +00:00
// Intersection retourne la période commune entre deux périodes.
func (r1 Range[C]) Intersection(r2 Range[C]) (result Option[Range[C]]) {
if r1.Overlaps(r2) {
result = Some(NewRange(Max(r1.begin, r2.begin), Min(r1.end, r2.end)))
2023-10-31 10:18:00 +00:00
}
return
}
2023-11-03 19:33:26 +00:00
// Joins retourne la plus grande période contiguë formée par deux périodes.
func (r1 Range[C]) Joins(r2 Range[C]) (result Option[Range[C]]) {
if r1.begin.Le(r2.end) && r1.end.Ge(r2.begin) {
result = Some(NewRange(Min(r1.begin, r2.begin), Max(r1.end, r2.end)))
2023-10-31 10:18:00 +00:00
}
return
}
2023-11-03 19:33:26 +00:00
// Diff retourne la liste des périodes qui ne se chevauchent pas.
func (r1 Range[C]) Diff(r2 Range[C]) (result []Range[C]) {
if r1.begin.Ne(r2.begin) {
begin := Min(r1.begin, r2.begin)
var end C
if begin.Eq(r1.begin) {
end = Min(r1.end, r2.begin)
2023-10-31 10:18:00 +00:00
} else {
2023-11-03 19:33:26 +00:00
end = Min(r2.end, r1.begin)
2023-10-31 10:18:00 +00:00
}
result = append(result, NewRange(begin, end))
}
2023-11-03 19:33:26 +00:00
if r1.end.Ne(r2.end) {
end := Max(r1.end, r2.end)
var begin C
if end.Eq(r1.end) {
begin = Max(r1.begin, r2.end)
2023-10-31 10:18:00 +00:00
} else {
2023-11-03 19:33:26 +00:00
begin = Max(r2.begin, r1.end)
2023-10-31 10:18:00 +00:00
}
result = append(result, NewRange(begin, end))
}
return
}