4 # :title: rbot time parsing utilities
6 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
8 # These routines read a string and return the number of seconds they
14 FLOAT_RX = /((?:\d*\.)?\d+)/
28 ONE_TO_NINE_RX = Regexp.new ONE_TO_NINE.keys.join('|')
45 TEENS_ETC_RX = Regexp.new TEENS_ETC.keys.join('|')
55 ENTIES_RX = Regexp.new ENTIES.keys.join('|')
57 LITNUM_RX = /(#{ONE_TO_NINE_RX})|(#{TEENS_ETC_RX})|(#{ENTIES_RX})\s*(#{ONE_TO_NINE_RX})?/
65 :"a quarter of" => 0.25,
66 :"a quarter of a" => 0.25,
67 :"a quarter of an" => 0.25,
68 :"three quarter" => 0.75,
69 :"three quarters" => 0.75,
70 :"three quarter of" => 0.75,
71 :"three quarters of" => 0.75,
72 :"three quarter of a" => 0.75,
73 :"three quarters of a" => 0.75,
74 :"three quarter of an" => 0.75,
75 :"three quarters of an" => 0.75,
78 FRACTION_RX = Regexp.new FRACTIONS.keys.join('|')
80 UNITSPEC_RX = /(years?|months?|s(?:ec(?:ond)?s?)?|m(?:in(?:ute)?s?)?|h(?:(?:ou)?rs?)?|d(?:ays?)?|weeks?)/
82 # str must much UNITSPEC_RX
83 def ParseTime.time_unit(str)
106 # example: half an hour, two and a half weeks, 5 seconds, an hour and 5 minutes
107 def ParseTime.parse_period(str)
108 clean = str.gsub(/\s+/, ' ').strip
112 if clean.sub!(/^(#{FRACTION_RX})\s+#{UNITSPEC_RX}/, '')
113 # fraction followed by unit
114 num = FRACTIONS[$1.intern]
115 unit = ParseTime.time_unit($2)
116 elsif clean.sub!(/^#{FLOAT_RX}\s*(?:\s+and\s+(#{FRACTION_RX})\s+)?#{UNITSPEC_RX}/, '')
117 # float plus optional fraction followed by unit
120 unit = ParseTime.time_unit($3)
122 if frac.nil? and clean.sub!(/^and\s+(#{FRACTION_RX})/, '')
126 num += FRACTIONS[frac.intern]
128 elsif clean.sub!(/^(?:#{LITNUM_RX})\s+(?:and\s+(#{FRACTION_RX})\s+)?#{UNITSPEC_RX}/, '')
130 num = ONE_TO_NINE[$1.intern]
132 num = TEENS_ETC[$2.intern]
134 num = ENTIES[$3.intern]
136 num += ONE_TO_NINE[$4.intern]
140 unit = ParseTime.time_unit($6)
142 if frac.nil? and clean.sub!(/^and\s+(#{FRACTION_RX})/, '')
146 num += FRACTIONS[frac.intern]
149 raise "invalid time string: #{clean} (parsed #{sofar} so far)"
152 clean.sub!(/^and\s+/, '')
157 # TODO 'at hh:mm:ss', 'next week, 'tomorrow', 'saturday' etc
160 def Utils.parse_time_offset(str)
162 when /^(\d+):(\d+)(?:\:(\d+))?$/ # TODO refactor
167 later = Time.mktime(now.year, now.month, now.day, hour, min, sec)
169 # if the given hour is earlier than current hour, given timestr
170 # must have been meant to be in the future
171 if hour < now.hour || hour <= now.hour && min < now.min
176 when /^(\d+):(\d+)(am|pm)$/ # TODO refactor
184 later = Time.mktime(now.year, now.month, now.day, hour, min, now.sec)
187 ParseTime.parse_period(str)