class EDTF::Interval

An interval behaves like a regular Range but is dedicated to EDTF dates. Most importantly, intervals use the date’s precision when generating the set of contained values and for membership tests. All tests are implemented without iteration and should therefore be considerably faster than if you were to use a regular Range.

For example, the interval “2003/2006” covers the years 2003, 2004, 2005 and 2006. Converting the interval to an array would result in a an array containing exactly four dates with year precision. This is also reflected in membership tests.

Date.edtf('2003/2006').length                           -> 4

Date.edtf('2003/2006').include? Date.edtf('2004')       -> true
Date.edtf('2003/2006').include? Date.edtf('2004-03')    -> false

Date.edtf('2003/2006').cover? Date.edtf('2004-03')      -> true

Attributes

from[R]
to[R]

Public Class Methods

new(from = Date.today, to = :open) click to toggle source
   # File lib/edtf/interval.rb
34 def initialize(from = Date.today, to = :open)
35   self.from, self.to = from, to
36 end

Public Instance Methods

<=>(other) click to toggle source
    # File lib/edtf/interval.rb
268 def <=>(other)
269   case other
270   when Interval, Season, Epoch
271     [min, max] <=> [other.min, other.max]
272   when Date
273     cover?(other) ? min <=> other : 0
274   else
275     nil
276   end
277 end
===(other) click to toggle source
    # File lib/edtf/interval.rb
279 def ===(other)
280   case other
281   when Interval
282     cover?(other.min) && cover?(other.max)
283   when Date
284     cover?(other)
285   else
286     false
287   end
288 end
begin() click to toggle source
    # File lib/edtf/interval.rb
231 def begin
232   min
233 end
cover?(other) click to toggle source

Returns true if other is an element of the Interval, false otherwise. In contrast to include? and member? this method does not take into account the date’s precision.

    # File lib/edtf/interval.rb
163 def cover?(other)
164   return false unless other.is_a?(Date)
165 
166   other = other.day_precision
167 
168   case
169   when unknown_start?
170     max.day_precision! == other
171   when unknown_end?
172     min.day_precision! == other
173   when open_end?
174     min.day_precision! <= other
175   else
176     min.day_precision! <= other && other <= max.day_precision!
177   end
178 end
each(&block) click to toggle source
   # File lib/edtf/interval.rb
94 def each(&block)
95   step(1, &block)
96 end
edtf() click to toggle source

Returns the Interval as an EDTF string.

    # File lib/edtf/interval.rb
292 def edtf
293   [
294     from.send(from.respond_to?(:edtf) ? :edtf : :to_s),
295     to.send(to.respond_to?(:edtf) ? :edtf : :to_s)
296   ] * '/'
297 end
Also aliased as: to_s
end() click to toggle source
    # File lib/edtf/interval.rb
264 def end
265   max
266 end
exclude_end?() click to toggle source

This method always returns false for Range compatibility. EDTF intervals always include the last date.

    # File lib/edtf/interval.rb
134 def exclude_end?
135   false
136 end
first → Date or nil click to toggle source
first(n) → Array

Returns the first date in the interval, or the first n dates.

    # File lib/edtf/interval.rb
185 def first(n = 1)
186   if n > 1
187     (ds = Array(min)).empty? ? ds : ds.concat(ds[0].next(n - 1))
188   else
189     min
190   end
191 end
from=(date) click to toggle source
   # File lib/edtf/interval.rb
38 def from=(date)
39   case date
40   when Date, :unknown
41     @from = date
42   else
43     throw ArgumentError.new("Intervals cannot start with: #{date}")
44   end
45 end
include?(other) click to toggle source

Returns true if other is an element of the Interval, false otherwise. Comparision is done according to the Interval’s min/max date and precision.

    # File lib/edtf/interval.rb
155 def include?(other)
156   cover?(other) && precision == other.precision
157 end
Also aliased as: member?
last → Date or nil click to toggle source
last(n) → Array

Returns the last date in the interval, or the last n dates.

    # File lib/edtf/interval.rb
198 def last(n = 1)
199   if n > 1
200     (ds = Array(max)).empty? ? ds : ds.concat(ds[0].prev(n - 1))
201   else
202     max
203   end
204 end
max → Date or nil click to toggle source
max { |a,b| block } → Date or nil

Returns the maximum value in the interval. If a block is given, it is used to compare values (slower). Returns nil if the first date of the interval is larger than the last or if the interval has an unknown or open end.

To calculate the dates, precision is taken into account. Thus, the max Date of “2007/2008” would be 2008-12-31, whilst the max Date of “2007-12/2008-10” would be 2009-10-31.

    # File lib/edtf/interval.rb
247 def max(&block)
248   if block_given?
249     to_a.max(&block)
250   else
251     case
252     when open_end?, unknown_end?, !unknown_start? && to < from
253       nil
254     when to.day_precision?
255       to
256     when to.month_precision?
257       to.end_of_month
258     else
259       to.end_of_year
260     end
261   end
262 end
member?(other)
Alias for: include?
min → Date or nil click to toggle source
min { |a,b| block } → Date or nil

Returns the minimum value in the interval. If a block is given, it is used to compare values (slower). Returns nil if the first date of the interval is larger than the last or if the interval has an unknown or open start.

    # File lib/edtf/interval.rb
214 def min(&block)
215   if block_given?
216     to_a.min(&block)
217   else
218     case
219     when unknown_start?, !unknown_end? && !open? && to < from
220       nil
221     when from.day_precision?
222       from
223     when from.month_precision?
224       from.beginning_of_month
225     else
226       from.beginning_of_year
227     end
228   end
229 end
mixed_precision?() click to toggle source

Returns true if the precisions of start and end date are not the same.

   # File lib/edtf/interval.rb
90 def mixed_precision?
91   min.precision != max.precision
92 end
precision() click to toggle source

Returns the intervals precision. Mixed precisions are currently not supported; in that case, the start date’s precision takes precedence.

   # File lib/edtf/interval.rb
85 def precision
86   min.precision || max.precision
87 end
step(by=1) { |date| block } → self click to toggle source
step(by=1) → Enumerator

Iterates over the interval by passing by elements at each step and yielding each date to the passed-in block. Note that the semantics of by are precision dependent: e.g., a value of 2 can mean 2 days, 2 months, or 2 years.

If not block is given, returns an enumerator instead.

    # File lib/edtf/interval.rb
110 def step(by = 1)
111   raise ArgumentError unless by.respond_to?(:to_i)
112 
113   if block_given?
114     f, t, by = min, max, by.to_i
115 
116     unless f.nil? || t.nil? || by < 1
117       by = { Date::PRECISIONS[precision] => by }
118 
119       until f > t do
120         yield f
121         f = f.advance(by)
122       end
123     end
124 
125     self
126   else
127     enum_for(:step, by)
128   end
129 end
to=(date) click to toggle source
   # File lib/edtf/interval.rb
47 def to=(date)
48   case date
49   when Date, :unknown, :open
50     @to = date
51   else
52     throw ArgumentError.new("Intervals cannot end with: #{date}")
53   end
54 end
to_range() click to toggle source

Returns the Interval as a Range.

    # File lib/edtf/interval.rb
143 def to_range
144   case
145   when open?, unknown?
146     nil
147   else
148     Range.new(unknown_start? ? Date.new : @from, max)
149   end
150 end
to_s()
Alias for: edtf
unknown?() click to toggle source
   # File lib/edtf/interval.rb
79 def unknown?
80   unknown_start? || unknown_end?
81 end
unknown_start!() click to toggle source
   # File lib/edtf/interval.rb
74 def unknown_start!
75   @from = :unknown
76   self
77 end
unknown_start?() click to toggle source
   # File lib/edtf/interval.rb
70 def unknown_start?
71   from == :unknown
72 end