Class: AIXM::Schedule::Time
Overview
The DATELESS_DATE is used to mark the date of the internal Time“ object irrelevant. However, Ruby does not persist end of days as 24:00, therefore {DATELESS_DATE} 1 marks this case.
Times suitable for schedules
This class implements the bare minimum of stdlib Time
and adds some extensions:
-
converts to UTC
-
date, seconds and milliseconds are ignored
-
#covered_by? to check whether schedule time falls within range of times
Shortcuts:
-
AIXM::BEGINNING_OF_DAY
- midnight expressed as “00:00” -
AIXM::END_OF_DAY
- midnight expressed as “24:00”
Constant Summary collapse
- EVENTS =
{ sunrise: :up, sunset: :down }.freeze
- PRECEDENCES =
{ first: :min, last: :max }.freeze
- DATELESS_DATE =
::Date.parse('0001-01-01').freeze
Instance Attribute Summary collapse
-
#delta ⇒ Integer?
readonly
Minutes added or subtracted from event.
-
#event ⇒ Symbol?
readonly
Event or alternative to time.
-
#precedence ⇒ Symbol?
readonly
Precedence of time vs.
- #time ⇒ Object private
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Whether two times are equal.
-
#at(hour: nil, min: nil, wrap: false) ⇒ AIXM::Schedule::Date
Creates a new time with the given parts altered.
-
#covered_by?(other) ⇒ Boolean
Whether this schedule time falls within the given range of schedule times.
-
#hour ⇒ Integer
Hour from 0 (beginning of day) to 24 (end of day).
-
#initialize(time_or_event, or: nil, plus: 0, minus: 0, whichever_comes: :first) ⇒ Time
constructor
Parse the given representation of time.
- #inspect ⇒ Object
- #min ⇒ Integer
-
#resolve(on:, xy:, round: nil) ⇒ AIXM::Schedule::Time, self
Resolve event to simple time.
-
#resolved? ⇒ Boolean
Whether this time is resolved and doesn’t contain an event (anymore).
-
#round(up: nil, down: nil) ⇒ AIXM::Schedule::Time, self
Round this time up or down.
-
#sortable? ⇒ Boolean
Whether this schedule time is sortable.
-
#to_s(format = '%R %z %o %E %P') ⇒ String
Human readable representation.
-
#to_time ⇒ Time
Stdlib Time equivalent using the value of DATELESS_DATE to represent a time only.
Methods included from Concerns::HashEquality
Constructor Details
#initialize(time_or_event, or: nil, plus: 0, minus: 0, whichever_comes: :first) ⇒ Time
Unlike its twin from the stdlib, this class differs between AIXM.time(‘00:00’) (beginning of day) and AIXM.time(‘24:00’) (end of day).
Parse the given representation of time.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/aixm/schedule/time.rb', line 74 def initialize(time_or_event, or: nil, plus: 0, minus: 0, whichever_comes: :first) alternative_event = binding.local_variable_get(:or) # necessary since "or" is a keyword @time = @event = @precedence = nil case time_or_event when Symbol self.event = time_or_event when ::Time, ::DateTime time_or_event = time_or_event.to_time set_time(time_or_event.hour, time_or_event.min, time_or_event.utc_offset) when /\A(\d{2}):?(\d{2}) ?([+-]\d{2}:?\d{2}|UTC)?\z/ set_time($1, $2, $3) else fail(ArgumentError, "time or event not recognized") end fail(ArgumentError, "only one event allowed") if event && alternative_event self.event ||= alternative_event @delta = event ? plus - minus : 0 if @time && event self.precedence = whichever_comes fail(ArgumentError, "mandatory precedence missing") unless precedence end end |
Instance Attribute Details
#delta ⇒ Integer? (readonly)
Minutes added or subtracted from event
45 46 47 |
# File 'lib/aixm/schedule/time.rb', line 45 def delta @delta end |
#event ⇒ Symbol?
Event or alternative to time
40 41 42 |
# File 'lib/aixm/schedule/time.rb', line 40 def event @event end |
#precedence ⇒ Symbol?
Precedence of time vs. event
50 51 52 |
# File 'lib/aixm/schedule/time.rb', line 50 def precedence @precedence end |
#time ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
35 36 37 |
# File 'lib/aixm/schedule/time.rb', line 35 def time @time end |
Instance Method Details
#==(other) ⇒ Boolean
Whether two times are equal.
215 216 217 |
# File 'lib/aixm/schedule/time.rb', line 215 def ==(other) to_s == other.to_s end |
#at(hour: nil, min: nil, wrap: false) ⇒ AIXM::Schedule::Date
Creates a new time with the given parts altered.
134 135 136 137 138 139 140 141 |
# File 'lib/aixm/schedule/time.rb', line 134 def at(hour: nil, min: nil, wrap: false) return self unless hour || min min ||= time.min hour ||= time.hour hour = hour + 1 if wrap && min < time.min hour = hour % 24 unless min.zero? self.class.new("%02d:%02d" % [hour, min]) end |
#covered_by?(other) ⇒ Boolean
Whether this schedule time falls within the given range of schedule times.
234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/aixm/schedule/time.rb', line 234 def covered_by?(other) range = Range.from(other) case when !sortable? || !range.first.sortable? || !range.last.sortable? fail "includes unsortables" when range.min range.first.to_s <= self.to_s && self.to_s <= range.last.to_s else range.first.to_s <= self.to_s || self.to_s <= range.last.to_s end end |
#hour ⇒ Integer
Hour from 0 (beginning of day) to 24 (end of day)
204 205 206 |
# File 'lib/aixm/schedule/time.rb', line 204 def hour @time.hour + (end_of_day? ? 24 : 0) end |
#inspect ⇒ Object
118 119 120 |
# File 'lib/aixm/schedule/time.rb', line 118 def inspect %Q(#<#{self.class} #{to_s}>) end |
#min ⇒ Integer
210 |
# File 'lib/aixm/schedule/time.rb', line 210 def_delegators :@time, :min |
#resolve(on:, xy:, round: nil) ⇒ AIXM::Schedule::Time, self
Resolve event to simple time
-
If
self
doesn’t have any event,self
is returned. -
Otherwise a new time is created with the event resolved for the given date and geographical location.
159 160 161 162 163 164 165 166 167 168 |
# File 'lib/aixm/schedule/time.rb', line 159 def resolve(on:, xy:, round: nil) if resolved? self else sun_time = self.class.new(Sun.send(event, on.to_date, xy.lat, xy.long).utc + (delta * 60)) sun_time = self.class.new([sun_time.time, self.time].send(PRECEDENCES.fetch(precedence))) if time sun_time = sun_time.round(EVENTS.fetch(event) => round) if round sun_time end end |
#resolved? ⇒ Boolean
Whether this time is resolved and doesn’t contain an event (anymore).
173 174 175 |
# File 'lib/aixm/schedule/time.rb', line 173 def resolved? !event end |
#round(up: nil, down: nil) ⇒ AIXM::Schedule::Time, self
Round this time up or down.
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/aixm/schedule/time.rb', line 182 def round(up: nil, down: nil) step = up || down || fail(ArgumentError, "either up or down is mandatory") rounded_min = min / step * step if rounded_min == min self else rounded_min = (rounded_min + step) % 60 if up at(min: rounded_min, wrap: !!up) end end |
#sortable? ⇒ Boolean
Whether this schedule time is sortable.
222 223 224 |
# File 'lib/aixm/schedule/time.rb', line 222 def sortable? !event end |
#to_s(format = '%R %z %o %E %P') ⇒ String
Human readable representation
The format recognises does the following interpolations:
-
%R - “HH:MM” in UTC if time is present, “” otherwise
-
%z - “UTC” if time is present, “” otherwise
-
%o - “or” if both time and event are present, “” otherwise
-
%E - “sunrise-15min” if no event is present, “” otherwise
-
%P - “whichever comes first” if precedence is present, “” otherwise
108 109 110 111 112 113 114 115 116 |
# File 'lib/aixm/schedule/time.rb', line 108 def to_s(format='%R %z %o %E %P') format.gsub(/%[RzoEP]/, '%R' => (sprintf("%02d:%02d", hour, min) if @time), '%z' => ('UTC' if @time), '%o' => ('or' if @time && event), '%E' => "#{event}#{sprintf("%+dmin", delta) unless delta.zero?}", '%P' => ("whichever comes #{precedence}" if precedence) ).compact end |
#to_time ⇒ Time
Stdlib Time equivalent using the value of DATELESS_DATE to represent a time only.
197 198 199 |
# File 'lib/aixm/schedule/time.rb', line 197 def to_time @time end |