-
Notifications
You must be signed in to change notification settings - Fork 10
/
MPInterval.ts
60 lines (51 loc) · 1.67 KB
/
MPInterval.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import {Interval} from 'luxon'
import type {Mutable} from 'type-fest'
import {MPDate} from './MPDate'
import {SCHelpers} from './schrono-utils'
/**
* TODO:
* - [ ] Support open-ended intervals with Infinity on either side
* - Expression such as since 2020 or until 2019
*/
// type ISOMPInterval = string
export type MPIntervalExpression = string
export interface MPInterval extends Interval {
/** Expression input. Will be used in `unparse` if provided */
readonly expression: string | undefined
/** Basically `toStandard`. Will preserve relative date, fall back to ISO */
unparse(opt?: {abs?: boolean}): string
}
export const MPInterval = {
create(_int: Interval, exp: MPIntervalExpression | undefined): MPInterval {
const interval = _int as Mutable<MPInterval>
interval.expression = exp
interval.unparse = function (opts) {
return this.expression != null && !opts?.abs
? this.expression
: this.toISO()
}
return interval
},
// MARK: - Static methods
parse(input: string) {
const mpd = MPDate.fromISO(input)
if (mpd.isValid) {
return this.create(mpd.toInterval(), undefined)
}
return this.fromNaturalExpression(input)
},
// TODO: Add toISO method
/** Prefer `fromString` to this, which handles ISO too */
fromNaturalExpression(exp: MPIntervalExpression) {
const [res] = SCHelpers.chronoParse(exp)
if (!res) {
return null
}
const start = MPDate.fromChronoComponents(res.start, res.text)
const end = res.end && MPDate.fromChronoComponents(res.end, res.text)
return this.create(
end ? Interval.fromDateTimes(start, end) : start.toInterval(),
res.text,
)
},
}