Class: Sniff::Timeframe
- Inherits:
-
Object
- Object
- Sniff::Timeframe
- Defined in:
- lib/sniff/timeframe.rb
Instance Attribute Summary collapse
-
#from ⇒ Object
Returns the value of attribute from.
-
#to ⇒ Object
Returns the value of attribute to.
Class Method Summary collapse
- .constrained_new(from, to, constraint) ⇒ Object
-
.mid(number) ⇒ Object
create a multiyear timeframe +/- number of years around today.
- .multiyear(from, to) ⇒ Object
- .this_year ⇒ Object
Instance Method Summary collapse
-
#&(other_timeframe) ⇒ Object
Returns a timeframe representing the intersection of the timeframes.
-
#/(other_timeframe) ⇒ Object
Returns a fraction of another Timeframe.
-
#==(other) ⇒ Object
(also: #eql?)
Returns true when this timeframe is equal to the other timeframe.
- #covered_by?(*timeframes) ⇒ Boolean
- #crop(container) ⇒ Object
-
#days ⇒ Object
The number of days in the timeframe.
-
#ending_no_later_than(date) ⇒ Object
multiyear safe.
-
#full_month_subtimeframes ⇒ Object
multiyear safe.
-
#full_year_subtimeframes ⇒ Object
multiyear safe.
- #gaps_left_by(*timeframes) ⇒ Object
-
#hash ⇒ Object
(also: #to_param)
Calculates a hash value for the Timeframe, used for equality checking and Hash lookups.
-
#include?(obj) ⇒ Boolean
Returns true when the date is included in this Timeframe.
-
#initialize(*args) ⇒ Timeframe
constructor
Creates a new instance of Timeframe.
- #inspect ⇒ Object
- #last_year ⇒ Object
-
#month_subtimeframes ⇒ Object
multiyear safe.
-
#months ⇒ Object
Returns an array of month-long subtimeframes TODO: rename to month_subtimeframes.
- #proper_include?(other_timeframe) ⇒ Boolean
-
#to_s ⇒ Object
Returns a string representation of the timeframe.
-
#year ⇒ Object
Returns the relevant year as a Timeframe.
-
#year_subtimeframes ⇒ Object
multiyear safe.
Constructor Details
#initialize(*args) ⇒ Timeframe
Creates a new instance of Timeframe. You can either pass a start and end Date or a Hash with named arguments, with the following options:
<tt>:month</tt>: Start date becomes the first day of this month, and the end date becomes the first day of
the next month. If no <tt>:year</tt> is specified, the current year is used.
<tt>:year</tt>: Start date becomes the first day of this year, and the end date becomes the first day of the
next year.
Examples:
Timeframe.new Date.new(2007, 2, 1), Date.new(2007, 4, 1) # February and March
Timeframe.new :year => 2004 # The year 2004
Timeframe.new :month => 4 # April
Timeframe.new :year => 2004, :month => 2 # Feburary 2004
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/sniff/timeframe.rb', line 27 def initialize(*args) = args. if month = [:month] month = Date.parse(month).month if month.is_a? String year = [:year] || Time.zone.today.year from = Date.new(year, month, 1) to = from.next_month elsif year = [:year] from = Date.new(year, 1, 1) to = Date.new(year+1, 1, 1) end from ||= args.shift.andand.to_date to ||= args.shift.andand.to_date raise ArgumentError, "Please supply a start and end date, `#{args.map(&:inspect).to_sentence}' is not enough" if from.nil? or to.nil? raise ArgumentError, "Start date #{from} should be earlier than end date #{to}" if from > to raise ArgumentError, 'Timeframes that cross year boundaries are dangerous' unless [:skip_year_boundary_crossing_check] or from.year == to.yesterday.year or from == to @from, @to = from, to end |
Instance Attribute Details
#from ⇒ Object
Returns the value of attribute from.
11 12 13 |
# File 'lib/sniff/timeframe.rb', line 11 def from @from end |
#to ⇒ Object
Returns the value of attribute to.
11 12 13 |
# File 'lib/sniff/timeframe.rb', line 11 def to @to end |
Class Method Details
.constrained_new(from, to, constraint) ⇒ Object
223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/sniff/timeframe.rb', line 223 def constrained_new(from, to, constraint) raise ArgumentError, 'Need Date, Date, Timeframe as args' unless from.is_a? Date and to.is_a? Date and constraint.is_a? Timeframe raise ArgumentError, "Start date #{from} should be earlier than end date #{to}" if from > to if to <= constraint.from or from >= constraint.to new constraint.from, constraint.from elsif from.year == to.yesterday.year new(from, to) & constraint elsif from.year < constraint.from.year and constraint.from.year < to.yesterday.year constraint else new [constraint.from, from].max, [constraint.to, to].min end end |
.mid(number) ⇒ Object
create a multiyear timeframe +/- number of years around today
244 245 246 247 248 |
# File 'lib/sniff/timeframe.rb', line 244 def mid(number) from = Time.zone.today - number.years to = Time.zone.today + number.years multiyear from, to end |
.multiyear(from, to) ⇒ Object
237 238 239 240 241 |
# File 'lib/sniff/timeframe.rb', line 237 def multiyear(from, to) from = Date.parse(from) if from.is_a?(String) to = Date.parse(to) if to.is_a?(String) new from, to, :skip_year_boundary_crossing_check => true end |
.this_year ⇒ Object
219 220 221 |
# File 'lib/sniff/timeframe.rb', line 219 def this_year new :year => Time.now.year end |
Instance Method Details
#&(other_timeframe) ⇒ Object
Returns a timeframe representing the intersection of the timeframes
163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/sniff/timeframe.rb', line 163 def &(other_timeframe) this_timeframe = self if other_timeframe == this_timeframe this_timeframe elsif this_timeframe.from > other_timeframe.from and this_timeframe.to < other_timeframe.to this_timeframe elsif other_timeframe.from > this_timeframe.from and other_timeframe.to < this_timeframe.to other_timeframe elsif this_timeframe.from >= other_timeframe.to or this_timeframe.to <= other_timeframe.from nil else Timeframe.new [this_timeframe.from, other_timeframe.from].max, [this_timeframe.to, other_timeframe.to].min, :skip_year_boundary_crossing_check => true end end |
#/(other_timeframe) ⇒ Object
Returns a fraction of another Timeframe
179 180 181 182 |
# File 'lib/sniff/timeframe.rb', line 179 def /(other_timeframe) raise ArgumentError, 'You can only divide a Timeframe by another Timeframe' unless other_timeframe.is_a? Timeframe self.days.to_f / other_timeframe.days.to_f end |
#==(other) ⇒ Object Also known as: eql?
Returns true when this timeframe is equal to the other timeframe
94 95 96 97 98 |
# File 'lib/sniff/timeframe.rb', line 94 def ==(other) # puts "checking to see if #{self} is equal to #{other}" if Emitter::DEBUG return false unless other.is_a?(Timeframe) from == other.from and to == other.to end |
#covered_by?(*timeframes) ⇒ Boolean
210 211 212 |
# File 'lib/sniff/timeframe.rb', line 210 def covered_by?(*timeframes) gaps_left_by(*timeframes).empty? end |
#crop(container) ⇒ Object
184 185 186 187 |
# File 'lib/sniff/timeframe.rb', line 184 def crop(container) raise ArgumentError, 'You can only crop a timeframe by another timeframe' unless container.is_a? Timeframe self.class.new [from, container.from].max, [to, container.to].min end |
#days ⇒ Object
59 60 61 |
# File 'lib/sniff/timeframe.rb', line 59 def days (to - from).to_i end |
#ending_no_later_than(date) ⇒ Object
multiyear safe
152 153 154 155 156 157 158 159 160 |
# File 'lib/sniff/timeframe.rb', line 152 def ending_no_later_than(date) if to < date self elsif from >= date nil else Timeframe.multiyear from, date end end |
#full_month_subtimeframes ⇒ Object
multiyear safe
133 134 135 |
# File 'lib/sniff/timeframe.rb', line 133 def full_month_subtimeframes month_subtimeframes.map { |st| Timeframe.new(:year => st.from.year, :month => st.from.month) } end |
#full_year_subtimeframes ⇒ Object
multiyear safe
145 146 147 148 149 |
# File 'lib/sniff/timeframe.rb', line 145 def full_year_subtimeframes (from.year..to.yesterday.year).map do |year| Timeframe.new :year => year end end |
#gaps_left_by(*timeframes) ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/sniff/timeframe.rb', line 189 def gaps_left_by(*timeframes) # remove extraneous timeframes timeframes.reject! { |t| t.to <= from } timeframes.reject! { |t| t.from >= to } # crop timeframes timeframes.map! { |t| t.crop self } # remove proper subtimeframes timeframes.reject! { |t| timeframes.detect { |u| u.proper_include? t } } # escape return [self] if timeframes.empty? timeframes.sort! { |x, y| x.from <=> y.from } timeframes.collect(&:to).unshift(from).ykk(timeframes.collect(&:from).push(to)) do |gap| Timeframe.new(*gap) if gap[1] > gap[0] end.compact end |
#hash ⇒ Object Also known as: to_param
Calculates a hash value for the Timeframe, used for equality checking and Hash lookups. This needs to be an integer or else it won’t use #eql?
103 104 105 |
# File 'lib/sniff/timeframe.rb', line 103 def hash from.hash + to.hash end |
#include?(obj) ⇒ Boolean
Returns true when the date is included in this Timeframe
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/sniff/timeframe.rb', line 75 def include?(obj) # puts "checking to see if #{date} is between #{from} and #{to}" if Emitter::DEBUG case obj when Date (from...to).include?(obj) when Time # (from...to).include?(obj.to_date) raise "this wasn't previously supported, but it could be" when Timeframe from <= obj.from and to >= obj.to end end |
#inspect ⇒ Object
50 51 52 |
# File 'lib/sniff/timeframe.rb', line 50 def inspect "<Timeframe(#{object_id}) #{days} days starting #{from} ending #{to}>" end |
#last_year ⇒ Object
214 215 216 |
# File 'lib/sniff/timeframe.rb', line 214 def last_year self.class.new((from - 1.year), (to - 1.year)) end |
#month_subtimeframes ⇒ Object
multiyear safe
124 125 126 127 128 129 130 |
# File 'lib/sniff/timeframe.rb', line 124 def month_subtimeframes (from.year..to.yesterday.year).map do |year| (1..12).map do |month| Timeframe.new(:year => year, :month => month) & self end end.flatten.compact end |
#months ⇒ Object
Returns an array of month-long subtimeframes TODO: rename to month_subtimeframes
110 111 112 113 114 115 |
# File 'lib/sniff/timeframe.rb', line 110 def months raise ArgumentError, "Please only provide whole-month timeframes to Timeframe#months" unless from.day == 1 and to.day == 1 raise ArgumentError, 'Timeframes that cross year boundaries are dangerous during Timeframe#months' unless from.year == to.yesterday.year year = from.year # therefore this only works in the from year (from.month..to.yesterday.month).map { |m| Timeframe.new :month => m, :year => year } end |
#proper_include?(other_timeframe) ⇒ Boolean
88 89 90 91 |
# File 'lib/sniff/timeframe.rb', line 88 def proper_include?(other_timeframe) raise ArgumentError, 'Proper inclusion only makes sense when testing other Timeframes' unless other_timeframe.is_a? Timeframe (from < other_timeframe.from) and (to > other_timeframe.to) end |
#to_s ⇒ Object
Returns a string representation of the timeframe
64 65 66 67 68 69 70 71 72 |
# File 'lib/sniff/timeframe.rb', line 64 def to_s if [from.day, from.month, to.day, to.month].uniq == [1] from.year.to_s elsif from.day == 1 and to.day == 1 and to.month - from.month == 1 "#{Date::MONTHNAMES[from.month]} #{from.year}" else "the period from #{from.strftime('%d %B')} to #{to.yesterday.strftime('%d %B %Y')}" end end |