@everwhen/temporal
Version:
_description_
87 lines (86 loc) • 2.9 kB
JavaScript
import { Duration } from "./duration.js";
import { parse, stringify } from "./fn/json.js";
import { assertIntervalLike, isIntervalLike, isPoint } from "./is.js";
import {} from "./point.js";
export class Interval {
start;
end;
constructor(start, end) {
this.start = start;
this.end = end;
this.validate();
}
static from(value) {
let intervalLike;
if (typeof value === 'string') {
const parsed = parse(value);
assertIntervalLike(parsed);
intervalLike = parsed;
}
else {
intervalLike = {
start: isPoint(value) ? value : value.start,
end: isPoint(value) ? value : value.end,
};
}
return new Interval(intervalLike.start, intervalLike.end);
}
static compare(a, b) {
const startComparison = a.start.compare(b.start);
if (startComparison !== 0) {
return startComparison;
}
return a.end.compare(b.end);
}
static overlaps(a, b, options) {
if (options?.inclusive) {
return a.start.compare(b.end) <= 0 && a.end.compare(b.start) >= 0;
}
return a.start.compare(b.end) < 0 && a.end.compare(b.start) > 0;
}
validate() {
if (this.start.compare(this.end) > 0) {
throw new Error(`Invalid interval: end (${this.end.toString()}) cannot be before start (${this.start.toString()})`);
}
}
isBefore(other) {
const otherPoint = isIntervalLike(other) ? other.start : other;
return this.end.compare(otherPoint) < 0;
}
isAfter(other) {
const otherPoint = isIntervalLike(other) ? other.end : other;
return this.start.compare(otherPoint) > 0;
}
equals(other) {
return this.start.equals(other.start) && this.end.equals(other.end);
}
overlaps(other, options) {
if (options?.inclusive) {
return (this.start.compare(other.end) <= 0 && this.end.compare(other.start) >= 0);
}
return (this.start.compare(other.end) < 0 && this.end.compare(other.start) > 0);
}
contains(value) {
if (isPoint(value)) {
return this.start.compare(value) <= 0 && this.end.compare(value) >= 0;
}
return (this.start.compare(value.start) <= 0 && this.end.compare(value.end) >= 0);
}
merge(other) {
const start = this.start.compare(other.start) <= 0 ? this.start : other.start;
const end = this.end.compare(other.end) >= 0 ? this.end : other.end;
return new Interval(start, end);
}
toJSON() {
return stringify({
start: this.start,
end: this.end,
});
}
toString() {
return `[${this.start.toString()}, ${this.end.toString()}]`;
}
get duration() {
return this.start.until(this.end);
}
}