Skip to content

Instantly share code, notes, and snippets.

@kevinvangelder
Created November 21, 2016 19:16
Show Gist options
  • Save kevinvangelder/7682bfb588545cadcbacb690a34b0b24 to your computer and use it in GitHub Desktop.
Save kevinvangelder/7682bfb588545cadcbacb690a34b0b24 to your computer and use it in GitHub Desktop.
Simple Time class for string-only time in Ruby
class SimpleTime
# attr_accessor :time
def self.parse(time)
return time if time.is_a?(SimpleTime)
return nil if time.nil? || (time.is_a?(String) && time.empty?)
return nil unless (time.is_a?(String) && time.upcase.match(/\d{1,2}:\d{2} [AP]M/)) || (time.is_a?(Hash) && time[:hour].present? && time[:minute].present? && time[:meridiem].present?)
self.new(time)
end
def initialize(time)
@time = parse(time) if time.is_a?(String)
@time ||= time if time.is_a?(Hash) && time[:hour].present? && time[:minute].present? && time[:meridiem].present?
end
def to_s
"#{hour}:#{minute.to_s.rjust(2, '0')} #{meridiem}"
end
def absolute_hour
case meridiem
when "AM"
return 25 if hour == 1
return 24 if hour == 12
return hour
when "PM"
return hour if hour == 12
return hour + 12
end
end
def hour
@time[:hour]
end
alias :hours :hour
def minute
@time[:minute]
end
alias :minutes :minute
def meridiem
@time[:meridiem]
end
def -(other_time)
return nil unless other_time.is_a?(SimpleTime)
return false if other_time > self
result = { hour: nil, minute: nil, meridiem: nil }
abs_hour = absolute_hour - other_time.absolute_hour - minute_adjustment(minute, other_time.minute)
result[:hour] = relative_hour(abs_hour)
result[:minute] = minute - other_time.minute if minute > other_time.minute || minute == other_time.minute
result[:minute] ||= minute + 60 - other_time.minute
result[:meridiem] = relative_meridiem(abs_hour)
SimpleTime.new(result)
end
def ==(other_time)
return false unless other_time.is_a?(SimpleTime)
hour == other_time.hour && minute == other_time.minute && meridiem == other_time.meridiem
end
def >(other_time)
return nil unless other_time.is_a?(SimpleTime)
return false if self == other_time
absolute_hour >= other_time.absolute_hour && minute >= other_time.minute
end
def <(other_time)
return nil unless other_time.is_a?(SimpleTime)
return false if self == other_time
(absolute_hour <= other_time.absolute_hour) || ((absolute_hour == other_time.absolute_hour) && (minute > other_time.minute))
end
def <=(other_time)
return nil unless other_time.is_a?(SimpleTime)
return true if self == other_time
absolute_hour <= other_time.absolute_hour && minute <= other_time.minute
end
def >=(other_time)
return nil unless other_time.is_a?(SimpleTime)
return true if self == other_time
absolute_hour >= other_time.absolute_hour && minute >= other_time.minute
end
def <=>(other_time)
if self > other_time
1
elsif self < other_time
-1
else
0
end
end
private
def parse(time)
return nil unless time.upcase.match(/\d{1,2}:\d{2} [AP]M/)
hours = time.match(/(\d{1,2}):/)[1].to_i
minutes = time.match(/:(\d{2})/)[1].to_i
meridiem = time.upcase.match(/ ([AP][M])/)[1]
{ hour: hours, minute: minutes, meridiem: meridiem }
end
def relative_hour(abs_hour)
case
when abs_hour <= 12 then abs_hour
when abs_hour <= 24 then abs_hour - 12
when abs_hour == 25 then abs_hour - 24
end
end
def relative_meridiem(abs_hour)
case
when abs_hour < 12 then "AM"
when abs_hour < 24 then "PM"
when abs_hour == 25 then "AM"
end
end
def minute_adjustment(mins, mins2)
return 0 if mins > mins2 || mins == mins2
1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment