module ChronicDuration
Constants
- FULL_WEEKS_PER_MONTH
On average, there's a little over 4 weeks in month.
- VERSION
'0.10.6' is the versioning used in 'github.com/henrypoydar/chronic_duration', we are adding revision part to highlight GitLab changes, e.g. '0.10.6.N'
Public Class Methods
days_per_month()
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 33 def self.days_per_month @@days_per_month end
days_per_month=(value)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 37 def self.days_per_month=(value) @@days_per_month = value end
hours_per_day()
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 25 def self.hours_per_day @@hours_per_day end
hours_per_day=(value)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 29 def self.hours_per_day=(value) @@hours_per_day = value end
raise_exceptions()
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 17 def self.raise_exceptions !!@@raise_exceptions end
raise_exceptions=(value)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 21 def self.raise_exceptions=(value) @@raise_exceptions = !!value end
Public Instance Methods
output(seconds, opts = {})
click to toggle source
Given an integer and an optional format, returns a formatted string representing elapsed time
# File lib/gitlab_chronic_duration.rb, line 51 def output(seconds, opts = {}) int = seconds.to_i seconds = int if seconds - int == 0 # if seconds end with .0 opts[:format] ||= :default opts[:keep_zero] ||= false hours_per_day = opts[:hours_per_day] || ChronicDuration.hours_per_day days_per_month = opts[:days_per_month] || ChronicDuration.days_per_month days_per_week = days_per_month / FULL_WEEKS_PER_MONTH years = months = weeks = days = hours = minutes = 0 decimal_places = seconds.to_s.split('.').last.length if seconds.is_a?(Float) minute = 60 hour = 60 * minute day = hours_per_day * hour month = days_per_month * day year = 31557600 if seconds >= 31557600 && seconds%year < seconds%month years = seconds / year months = seconds % year / month days = seconds % year % month / day hours = seconds % year % month % day / hour minutes = seconds % year % month % day % hour / minute seconds = seconds % year % month % day % hour % minute elsif seconds >= 60 minutes = (seconds / 60).to_i seconds = seconds % 60 if minutes >= 60 hours = (minutes / 60).to_i minutes = (minutes % 60).to_i if !opts[:limit_to_hours] if hours >= hours_per_day days = (hours / hours_per_day).to_i hours = (hours % hours_per_day).to_i if opts[:weeks] if days >= days_per_week weeks = (days / days_per_week).to_i days = (days % days_per_week).to_i if weeks >= FULL_WEEKS_PER_MONTH months = (weeks / FULL_WEEKS_PER_MONTH).to_i weeks = (weeks % FULL_WEEKS_PER_MONTH).to_i end end else if days >= days_per_month months = (days / days_per_month).to_i days = (days % days_per_month).to_i end end end end end end joiner = opts.fetch(:joiner) { ' ' } process = nil case opts[:format] when :micro dividers = { :years => 'y', :months => 'mo', :weeks => 'w', :days => 'd', :hours => 'h', :minutes => 'm', :seconds => 's' } joiner = '' when :short dividers = { :years => 'y', :months => 'mo', :weeks => 'w', :days => 'd', :hours => 'h', :minutes => 'm', :seconds => 's' } when :default dividers = { :years => ' yr', :months => ' mo', :weeks => ' wk', :days => ' day', :hours => ' hr', :minutes => ' min', :seconds => ' sec', :pluralize => true } when :long dividers = { :years => ' year', :months => ' month', :weeks => ' week', :days => ' day', :hours => ' hour', :minutes => ' minute', :seconds => ' second', :pluralize => true } when :chrono dividers = { :years => ':', :months => ':', :weeks => ':', :days => ':', :hours => ':', :minutes => ':', :seconds => ':', :keep_zero => true } process = lambda do |str| # Pad zeros # Get rid of lead off times if they are zero # Get rid of lead off zero # Get rid of trailing : divider = ':' str.split(divider).map { |n| # add zeros only if n is an integer n.include?('.') ? ("%04.#{decimal_places}f" % n) : ("%02d" % n) }.join(divider).gsub(/^(00:)+/, '').gsub(/^0/, '').gsub(/:$/, '') end joiner = '' end result = [:years, :months, :weeks, :days, :hours, :minutes, :seconds].map do |t| next if t == :weeks && !opts[:weeks] num = eval(t.to_s) num = ("%.#{decimal_places}f" % num) if num.is_a?(Float) && t == :seconds keep_zero = dividers[:keep_zero] keep_zero ||= opts[:keep_zero] if t == :seconds humanize_time_unit( num, dividers[t], dividers[:pluralize], keep_zero ) end.compact! result = result[0...opts[:units]] if opts[:units] result = result.join(joiner) if process result = process.call(result) end result.length == 0 ? nil : result end
parse(string, opts = {})
click to toggle source
Given a string representation of elapsed time, return an integer (or float, if fractions of a second are input)
# File lib/gitlab_chronic_duration.rb, line 44 def parse(string, opts = {}) result = calculate_from_words(cleanup(string), opts) (!opts[:keep_zero] and result == 0) ? nil : result end
Private Instance Methods
calculate_from_words(string, opts)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 176 def calculate_from_words(string, opts) val = 0 words = string.split(' ') words.each_with_index do |v, k| if v =~ float_matcher val += (convert_to_number(v) * duration_units_seconds_multiplier(words[k + 1] || (opts[:default_unit] || 'seconds'), opts)) end end val end
cleanup(string)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 187 def cleanup(string) res = string.downcase res = filter_by_type(Numerizer.numerize(res)) res = res.gsub(float_matcher) {|n| " #{n} "}.squeeze(' ').strip res = filter_through_white_list(res) end
convert_to_number(string)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 194 def convert_to_number(string) string.to_f % 1 > 0 ? string.to_f : string.to_i end
duration_units_list()
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 198 def duration_units_list %w(seconds minutes hours days weeks months years) end
duration_units_seconds_multiplier(unit, opts)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 202 def duration_units_seconds_multiplier(unit, opts) return 0 unless duration_units_list.include?(unit) hours_per_day = opts[:hours_per_day] || ChronicDuration.hours_per_day days_per_month = opts[:days_per_month] || ChronicDuration.days_per_month days_per_week = days_per_month / FULL_WEEKS_PER_MONTH case unit when 'years'; 31557600 when 'months'; 3600 * hours_per_day * days_per_month when 'weeks'; 3600 * hours_per_day * days_per_week when 'days'; 3600 * hours_per_day when 'hours'; 3600 when 'minutes'; 60 when 'seconds'; 1 end end
filter_by_type(string)
click to toggle source
Parse 3:41:59 and return 3 hours 41 minutes 59 seconds
# File lib/gitlab_chronic_duration.rb, line 221 def filter_by_type(string) chrono_units_list = duration_units_list.reject {|v| v == "weeks"} if string.gsub(' ', '') =~ /#{float_matcher}(:#{float_matcher})+/ res = [] string.gsub(' ', '').split(':').reverse.each_with_index do |v,k| return unless chrono_units_list[k] res << "#{v} #{chrono_units_list[k]}" end res = res.reverse.join(' ') else res = string end res end
filter_through_white_list(string)
click to toggle source
Get rid of unknown words and map found words to defined time units
# File lib/gitlab_chronic_duration.rb, line 242 def filter_through_white_list(string) res = [] string.split(' ').each do |word| if word =~ float_matcher res << word.strip next end stripped_word = word.strip.gsub(/^,/, '').gsub(/,$/, '') if mappings.has_key?(stripped_word) res << mappings[stripped_word] elsif !join_words.include?(stripped_word) and ChronicDuration.raise_exceptions raise DurationParseError, "An invalid word #{word.inspect} was used in the string to be parsed." end end # add '1' at front if string starts with something recognizable but not with a number, like 'day' or 'minute 30sec' res.unshift(1) if res.length > 0 && mappings[res[0]] res.join(' ') end
float_matcher()
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 236 def float_matcher /[0-9]*\.?[0-9]+/ end
humanize_time_unit(number, unit, pluralize, keep_zero)
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 168 def humanize_time_unit(number, unit, pluralize, keep_zero) return nil if number == 0 && !keep_zero res = "#{number}#{unit}" # A poor man's pluralizer res << 's' if !(number == 1) && pluralize res end
join_words()
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 299 def join_words ['and', 'with', 'plus'] end
mappings()
click to toggle source
# File lib/gitlab_chronic_duration.rb, line 261 def mappings { 'seconds' => 'seconds', 'second' => 'seconds', 'secs' => 'seconds', 'sec' => 'seconds', 's' => 'seconds', 'minutes' => 'minutes', 'minute' => 'minutes', 'mins' => 'minutes', 'min' => 'minutes', 'm' => 'minutes', 'hours' => 'hours', 'hour' => 'hours', 'hrs' => 'hours', 'hr' => 'hours', 'h' => 'hours', 'days' => 'days', 'day' => 'days', 'dy' => 'days', 'd' => 'days', 'weeks' => 'weeks', 'week' => 'weeks', 'wks' => 'weeks', 'wk' => 'weeks', 'w' => 'weeks', 'months' => 'months', 'mo' => 'months', 'mos' => 'months', 'month' => 'months', 'years' => 'years', 'year' => 'years', 'yrs' => 'years', 'yr' => 'years', 'y' => 'years' } end