11using Base. Dates: value, coarserperiod
22
33"""
4- AnchoredInterval{T, P }(anchor::T, [inclusivity::Inclusivity]) -> AnchoredInterval{T, P}
5- AnchoredInterval{T, P }(anchor::T, [closed_left::Bool, closed_right::Bool]) -> AnchoredInterval{T, P}
4+ AnchoredInterval{T, S, E }(anchor::T, [span::S, inclusivity::Inclusivity])
5+ AnchoredInterval{T, S, E }(anchor::T, [span::S, closed_left::Bool, closed_right::Bool])
66
7- AnchoredInterval(anchor::T, P, [inclusivity::Inclusivity]) -> AnchoredInterval{T, P}
8- AnchoredInterval(anchor::T, P, [closed_left::Bool, closed_right::Bool]) -> AnchoredInterval{T, P}
7+ AnchoredInterval{T, S, E} (anchor::T, [inclusivity::Inclusivity])
8+ AnchoredInterval{T, S, E} (anchor::T, [closed_left::Bool, closed_right::Bool])
99
1010`AnchoredInterval` is a subtype of `AbstractInterval` that represents a non-iterable range
1111or span of values defined not by two endpoints but instead by a single `anchor` point and
@@ -24,8 +24,9 @@ included for positive values of `P` and the greater endpoint included for negati
2424range of values. This happens most often with dates and times, where "HE15" is often used as
2525shorthand for (14:00..15:00].
2626
27- To this end, `HourEnding` is a type alias for `AnchoredInterval{T, Hour(-1)} where T`.
28- Similarly, `HourBeginning` is a type alias for `AnchoredInterval{T, Hour(1)} where T`.
27+ To this end, `HourEnding` is a type alias for `AnchoredInterval{T, Hour, Ending} where T`.
28+ Similarly, `HourBeginning` is a type alias for
29+ `AnchoredInterval{T, Hour, Beginning} where T`.
2930
3031### Rounding
3132
@@ -52,41 +53,80 @@ HourBeginning{DateTime}(2016-08-11T02:00:00, Inclusivity(true, false))
5253
5354```julia
5455julia> AnchoredInterval(DateTime(2016, 8, 11, 12), Hour(-1))
55- HourEnding{DateTime}(2016-08-11T12:00:00, Inclusivity(false, true))
56+ HourEnding{DateTime}(2016-08-11T12:00:00, -1 hour, Inclusivity(false, true))
5657
5758julia> AnchoredInterval(DateTime(2016, 8, 11), Day(1))
58- AnchoredInterval{DateTime, 1 day }(2016-08-11T00:00:00, Inclusivity(true, false))
59+ AnchoredInterval{DateTime, Day, Beginning }(2016-08-11T00:00:00, 1 day , Inclusivity(true, false))
5960
6061julia> AnchoredInterval(DateTime(2016, 8, 11, 12, 30), Minute(5), true, true)
61- AnchoredInterval{DateTime, 5 minutes }(2016-08-11T12:30:00, Inclusivity(true, true))
62+ AnchoredInterval{DateTime, Minute, Beginning }(2016-08-11T12:30:00, 5 minutes , Inclusivity(true, true))
6263```
6364
6465See also: [`Interval`](@ref), [`Inclusivity`](@ref), [`HE`](@ref), [`HB`](@ref)
6566"""
66- struct AnchoredInterval{T, P } <: AbstractInterval{T}
67+ struct AnchoredInterval{T, S, E } <: AbstractInterval{T}
6768 anchor:: T
69+ span:: S
6870 inclusivity:: Inclusivity
71+
72+ function AnchoredInterval {T, S, E} (anchor:: T , span:: S , inc:: Inclusivity ) where {T, S, E}
73+ @assert E isa Direction
74+ if span < zero (S)
75+ @assert E == Ending
76+ elseif span > zero (S)
77+ @assert E == Beginning
78+ else
79+ @assert E isa Direction
80+ end
81+ @assert typeof (anchor + span) == T
82+ new {T, S, E} (anchor, span, inc)
83+ end
84+ end
85+
86+ function AnchoredInterval {T, S, E} (anchor:: T , span:: S , x:: Bool , y:: Bool ) where {T, S, E}
87+ AnchoredInterval {T, S, E} (anchor, span, Inclusivity (x, y))
88+ end
89+ function AnchoredInterval {T, S, E} (anchor:: T , span:: S ) where {T, S, E}
90+ # If an interval is anchored to the lesser endpoint, default to Inclusivity(false, true)
91+ # If an interval is anchored to the greater endpoint, default to Inclusivity(true, false)
92+ AnchoredInterval {T, S, E} (anchor, span, Inclusivity (span ≥ zero (S), span ≤ zero (S)))
93+ end
94+ function AnchoredInterval {T, S, E} (anchor:: T , inc:: Inclusivity ) where {T, S, E}
95+ span = E == Ending ? - oneunit (S) : oneunit (S)
96+ AnchoredInterval {T, S, E} (anchor, span, inc)
97+ end
98+ function AnchoredInterval {T, S, E} (anchor:: T , x:: Bool , y:: Bool ) where {T, S, E}
99+ AnchoredInterval {T, S, E} (anchor, Inclusivity (x, y))
100+ end
101+ function AnchoredInterval {T, S, E} (anchor:: T ) where {T, S, E}
102+ span = E == Ending ? - oneunit (S) : oneunit (S)
103+ AnchoredInterval {T, S, E} (anchor, span)
69104end
70105
71- # When an interval is anchored to the lesser endpoint, default to Inclusivity(false, true)
72- # When an interval is anchored to the greater endpoint, default to Inclusivity(true, false)
73- function AnchoredInterval {T, P} (i:: T ) where {T, P}
74- return AnchoredInterval {T, P} (i:: T , Inclusivity (P ≥ zero (P), P ≤ zero (P)))
106+ function AnchoredInterval {T, S} (anchor:: T , span:: S , args... ) where {T, S}
107+ E = if span < zero (S)
108+ Ending
109+ elseif span > zero (S)
110+ Beginning
111+ else
112+ throw (ArgumentError (" Must specify endpoint type when span is zero" ))
113+ end
114+ AnchoredInterval {T, S, E} (anchor, span, args... )
75115end
76116
77- function AnchoredInterval {T, P} (i :: T , x :: Bool , y :: Bool ) where {T, P }
78- return AnchoredInterval {T, P} (i, Inclusivity (x, y) )
117+ function AnchoredInterval {T} (anchor :: T , span :: S , args ... ) where {T, S }
118+ AnchoredInterval {T, S} (anchor, span, args ... )
79119end
80120
81- AnchoredInterval (i :: T , span, inc :: Inclusivity ) where T = AnchoredInterval {T, span} (i, inc)
82- AnchoredInterval (i :: T , span, x :: Bool , y :: Bool ) where T = AnchoredInterval {T, span} (i, x, y )
83- AnchoredInterval (i :: T , span) where T = AnchoredInterval {T, span} (i)
121+ function AnchoredInterval (anchor :: T , span:: S , args ... ) where {T, S}
122+ AnchoredInterval {T, S} (anchor, span, args ... )
123+ end
84124
85125
86- const HourEnding{T} = AnchoredInterval{T, Hour ( - 1 ) } where T <: TimeType
126+ const HourEnding{T} = AnchoredInterval{T, Hour, Ending } where T <: TimeType
87127HourEnding (a:: T , args... ) where T = HourEnding {T} (a, args... )
88128
89- const HourBeginning{T} = AnchoredInterval{T, Hour ( 1 ) } where T <: TimeType
129+ const HourBeginning{T} = AnchoredInterval{T, Hour, Beginning } where T <: TimeType
90130HourBeginning (a:: T , args... ) where T = HourBeginning {T} (a, args... )
91131
92132"""
@@ -105,22 +145,22 @@ nearest hour.
105145"""
106146HB (a, args... ) = HourBeginning (floor (a, Hour), args... )
107147
108- function Base. copy (x:: AnchoredInterval{T, P } ) where {T, P }
109- return AnchoredInterval {T, P } (anchor (x), inclusivity (x))
148+ function Base. copy (x:: AnchoredInterval{T, S, E } ) where {T, S, E }
149+ return AnchoredInterval {T, S, E } (anchor (x), inclusivity (x))
110150end
111151
112152# #### ACCESSORS #####
113153
114- function Base. first (interval:: AnchoredInterval{T, P} ) where {T, P}
115- min (interval. anchor, interval. anchor + P )
154+ function Base. first (interval:: AnchoredInterval )
155+ min (interval. anchor, interval. anchor + interval . span )
116156end
117157
118- function Base. last (interval:: AnchoredInterval{T, P} ) where {T, P}
119- max (interval. anchor, interval. anchor + P )
158+ function Base. last (interval:: AnchoredInterval )
159+ max (interval. anchor, interval. anchor + interval . span )
120160end
121161
122162anchor (interval:: AnchoredInterval ) = interval. anchor
123- span (interval:: AnchoredInterval{T, P} ) where {T, P} = abs (P )
163+ span (interval:: AnchoredInterval ) = abs (interval . span )
124164
125165# #### CONVERSION #####
126166
@@ -132,6 +172,19 @@ function Base.convert(::Type{Interval{T}}, interval::AnchoredInterval{T}) where
132172 return Interval {T} (first (interval), last (interval), inclusivity (interval))
133173end
134174
175+ # Conversion methods which currently aren't needed but could prove useful. Commented out
176+ # since these are untested.
177+
178+ #=
179+ function Base.convert(::Type{AnchoredInterval{Ending}}, interval::Interval{T}) where T
180+ AnchoredInterval{T}(last(interval), -span(interval), inclusivity(interval))
181+ end
182+
183+ function Base.convert(::Type{AnchoredInterval{Beginning}}, interval::Interval{T}) where T
184+ AnchoredInterval{T}(first(interval), span(interval), inclusivity(interval))
185+ end
186+ =#
187+
135188Base. convert (:: Type{T} , interval:: AnchoredInterval{T} ) where T = anchor (interval)
136189
137190# Date/DateTime attempt to convert to Int64 instead of falling back to convert(T, ...)
@@ -146,17 +199,21 @@ Base.show(io::IO, ::Type{HourBeginning}) = print(io, "HourBeginning{T}")
146199Base. show (io:: IO , :: Type{HourEnding{T}} ) where T <: TimeType = print (io, " HourEnding{$T }" )
147200Base. show (io:: IO , :: Type{HourBeginning{T}} ) where T <: TimeType = print (io, " HourBeginning{$T }" )
148201
149- function Base. show (io:: IO , :: Type{AnchoredInterval{T, P}} ) where {T, P}
150- print (io, " AnchoredInterval{$T , $P }" )
202+ function Base. show (io:: IO , :: Type{AnchoredInterval{T, S, E}} ) where {T, S, E}
203+ d = E == Beginning ? " Beginning" : " Ending"
204+ print (io, " AnchoredInterval{$T , $S , $d }" )
151205end
152206
153- function Base. show (io:: IO , interval:: T ) where T <: AnchoredInterval
207+ function Base. show (io:: IO , interval:: AnchoredInterval )
154208 if get (io, :compact , false )
155209 print (io, interval)
156210 else
157- print (io, " $T (" )
211+ show (io, typeof (interval))
212+ print (io, " (" )
158213 show (io, anchor (interval))
159214 print (io, " , " )
215+ show (io, interval. span)
216+ print (io, " , " )
160217 show (io, inclusivity (interval))
161218 print (io, " )" )
162219 end
173230
174231# #### ARITHMETIC #####
175232
176- Base.:+ (a:: T , b) where {T <: AnchoredInterval } = T (anchor (a) + b, inclusivity (a))
233+ Base.:+ (a:: T , b) where {T <: AnchoredInterval } = T (anchor (a) + b, a . span, inclusivity (a))
177234
178235Base.:+ (a, b:: AnchoredInterval ) = b + a
179236Base.:- (a:: AnchoredInterval , b) = a + - b
@@ -183,15 +240,20 @@ Base.:-(a::AnchoredInterval, b::AnchoredInterval) = anchor(a) - anchor(b)
183240
184241Base.:- (a:: T , b:: AnchoredInterval{T} ) where {T <: Number } = a + - b
185242
186- function Base.:- (a:: AnchoredInterval{T, P} ) where {T <: Number , P}
243+ function Base.:- (a:: AnchoredInterval{T, S, Ending} ) where {T <: Number , S}
244+ inc = inclusivity (a)
245+ AnchoredInterval {T, S, Beginning} (- anchor (a), - a. span, Inclusivity (last (inc), first (inc)))
246+ end
247+
248+ function Base.:- (a:: AnchoredInterval{T, S, Beginning} ) where {T <: Number , S}
187249 inc = inclusivity (a)
188- AnchoredInterval {T, -P } (- anchor (a), Inclusivity (last (inc), first (inc)))
250+ AnchoredInterval {T, S, Ending } (- anchor (a), - a . span , Inclusivity (last (inc), first (inc)))
189251end
190252
191253# #### EQUALITY #####
192254
193255# Required for min/max of AnchoredInterval{LaxZonedDateTime} when the anchor is AMB or DNE
194- function Base.:< (a:: AnchoredInterval{T, P } , b:: AnchoredInterval{T, P } ) where {T, P }
256+ function Base.:< (a:: AnchoredInterval{T, S, E } , b:: AnchoredInterval{T, S, E } ) where {T, S, E }
195257 return anchor (a) < anchor (b)
196258end
197259
@@ -203,8 +265,8 @@ function Base.steprem(a::T, b::T, c) where {T <: AnchoredInterval}
203265end
204266
205267# Infer step for two-argument StepRange{<:AnchoredInterval}
206- function Base. colon (start:: AnchoredInterval{T, P } , stop:: AnchoredInterval{T, P } ) where {T,P }
207- return colon (start, abs (P ), stop)
268+ function Base. colon (start:: AnchoredInterval{T, S } , stop:: AnchoredInterval{T, S } ) where {T,S }
269+ return colon (start, oneunit (S ), stop)
208270end
209271
210272function Base. length (r:: StepRange{<:AnchoredInterval} )
@@ -213,23 +275,23 @@ end
213275
214276# #### SET OPERATIONS #####
215277
216- function Base. isempty (interval:: AnchoredInterval{T, P } ) where {T, P }
217- return P == zero (P ) && ! isclosed (interval)
278+ function Base. isempty (interval:: AnchoredInterval{T, S } ) where {T, S }
279+ return span (interval) == zero (S ) && ! isclosed (interval)
218280end
219281
220- function Base. intersect (a:: AnchoredInterval{T, P } , b:: AnchoredInterval{T, Q } ) where {T,P,Q }
282+ function Base. intersect (a:: AnchoredInterval{T, S, E } , b:: AnchoredInterval{T, S, E } ) where {T, S, E }
221283 interval = invoke (intersect, Tuple{AbstractInterval{T}, AbstractInterval{T}}, a, b)
222284
223- sp = isa (P, Period) ? canonicalize (typeof (P) , span (interval)) : span (interval)
224- if P ≤ zero (P)
285+ sp = S <: Period ? canonicalize (S , span (interval)) : span (interval)
286+ if E == Ending
225287 anchor = last (interval)
226- new_P = - sp
288+ sp = - sp
227289 else
228290 anchor = first (interval)
229- new_P = sp
291+ sp = sp
230292 end
231293
232- return AnchoredInterval {T, new_P } (anchor, inclusivity (interval))
294+ return AnchoredInterval {T, S, E } (anchor, sp , inclusivity (interval))
233295end
234296
235297# #### UTILITIES #####
0 commit comments