module TimeCalc::Types
@private Tries to encapsulate all the differences between Time, Date, DateTime
Constants
- ATTRS
- CLASS_NAME
@private Because AS::TimeWithZone so frigging smart that it returns “Time” from redefined class name.
- REAL_TIMEZONE
Public Instance Methods
compare(v1, v2)
click to toggle source
# File lib/time_calc/types.rb, line 24 def compare(v1, v2) compatible?(v1, v2) ? v1 <=> v2 : v1.to_time <=> v2.to_time end
compatible?(v1, v2)
click to toggle source
# File lib/time_calc/types.rb, line 20 def compatible?(v1, v2) [v1, v2].all?(Date) || [v1, v2].all?(Time) end
convert(v, klass)
click to toggle source
# File lib/time_calc/types.rb, line 28 def convert(v, klass) return v if v.class == klass v.public_send("to_#{klass.name.downcase}") end
merge_activesupport__timewithzone(value, **attrs)
click to toggle source
# File lib/time_calc/types.rb, line 54 def merge_activesupport__timewithzone(value, **attrs) # You'd imagine we should be able to use just value.change(...) ActiveSupport's API here... # But it is not available if you don't require all the core_ext's of Time, so I decided to # be on the safe side and use similar approach everywhere. # When we truncate, we use :subsec key as a sign to zeroefy second fractions attrs[:sec_fraction] ||= attrs.delete(:subsec) if attrs.key?(:subsec) _merge(value, **attrs) .then { |components| zone = components.delete(:time_zone) components.merge!(mday: components.delete(:day), mon: components.delete(:month)) zone.__send__(:parts_to_time, components, value) } end
merge_date(value, **attrs)
click to toggle source
# File lib/time_calc/types.rb, line 41 def merge_date(value, **attrs) _merge(value, **attrs).values.then { |components| Date.new(*components) } end
merge_datetime(value, **attrs)
click to toggle source
# File lib/time_calc/types.rb, line 45 def merge_datetime(value, **attrs) # When we truncate, we use :subsec key as a sign to zeroefy second fractions attrs[:sec_fraction] ||= attrs.delete(:subsec) if attrs.key?(:subsec) _merge(value, **attrs) .tap { |h| h[:sec] += h.delete(:sec_fraction) } .values.then { |components| DateTime.new(*components) } end
merge_time(value, **attrs)
click to toggle source
# File lib/time_calc/types.rb, line 34 def merge_time(value, **attrs) _merge(value, **attrs) .tap { |h| h[:sec] += h.delete(:subsec) } .then { |h| fix_time_zone(h, value) } .values.then { |components| Time.new(*components) } end
Private Instance Methods
_merge(value, attrs)
click to toggle source
# File lib/time_calc/types.rb, line 86 def _merge(value, attrs) attr_names = ATTRS.fetch(CLASS_NAME.bind(value.class).call) attr_names.to_h { |u| [u, value.public_send(u)] }.merge(**attrs.slice(*attr_names)) end
fix_time_zone(attrs, origin)
click to toggle source
# File lib/time_calc/types.rb, line 74 def fix_time_zone(attrs, origin) case origin.zone when nil, '' # "" is JRuby's way to say "no zone known" attrs when String # Y U NO Hash#except, Ruby??? attrs.slice(*attrs.keys.-([:utc_offset])) # Then it would be default, then it would set system's zone when REAL_TIMEZONE attrs.merge(utc_offset: origin.zone) # When passed in place of utc_offset, timezone object becomes Time's zone end end