class Tins::Duration
def self.parse(string, template: '%S%d+%h:%m:%s.%f')
-
(Integer, Float)
- The number of (fractional) seconds of the duration.
Parameters:
-
template
(String
) -- for the duration format, see {#format}. -
string
(String
) -- The duration string to parse.
def self.parse(string, template: '%S%d+%h:%m:%s.%f') s, t = string.to_s.dup, template.dup d, sd = 0, 1 loop do t.sub!(/\A(%[Sdhmsf%]|.)/) { |directive| case directive when '%S' then s.sub!(/\A-?/) { sd *= -1 if _1 == ?-; '' } when '%d' then s.sub!(/\A\d+/) { d += 86_400 * _1.to_i; '' } when '%h' then s.sub!(/\A\d+/) { d += 3_600 * _1.to_i; '' } when '%m' then s.sub!(/\A\d+/) { d += 60 * _1.to_i; '' } when '%s' then s.sub!(/\A\d+/) { d += _1.to_i; '' } when '%f' then s.sub!(/\A\d+/) { d += Float(?. + _1); '' } when '%%' then if s[0] == ?% s[0] = '' else raise "expected %s, got #{s.inspect}" end else if directive == s[0] s[0] = '' else raise ArgumentError, "expected #{t.inspect}, got #{s.inspect}" end end '' } or break end sd * d end
def <=>(other)
def <=>(other) to_f <=> other.to_f end
def days?
def days? @days > 0 end
def format(template = '%S%d+%h:%m:%s.%f', precision: nil)
def format(template = '%S%d+%h:%m:%s.%f', precision: nil) result = template.gsub(/%[DdhmSs]/) { |directive| case directive when '%S' then ?- if negative? when '%d' then @days when '%h' then '%02u' % @hours when '%m' then '%02u' % @minutes when '%s' then '%02u' % @seconds when '%D' then format_smart end } if result.include?('%f') if precision fractional_seconds = "%.#{precision}f" % @fractional_seconds else fractional_seconds = '%f' % @fractional_seconds end result.gsub!('%f', fractional_seconds[2..-1]) end result end
def format_smart
def format_smart template = '%h:%m:%s' precision = nil if days? template.prepend '%d+' end if fractional_seconds? template << '.%f' precision = 3 end template.prepend '%S' format template, precision: precision end
def fractional_seconds?
def fractional_seconds? @fractional_seconds > 0 end
def hours?
def hours? @hours > 0 end
def initialize(seconds)
def initialize(seconds) @negative = seconds < 0 seconds = seconds.abs @original_seconds = seconds @days, @hours, @minutes, @seconds, @fractional_seconds = [ 86_400, 3600, 60, 1, 0 ].inject([ [], seconds ]) {|(r, s), d| if d > 0 dd, rest = s.divmod(d) r << dd [ r, rest ] else r << s end } end
def minutes?
def minutes? @minutes > 0 end
def negative?
def negative? @negative end
def seconds?
def seconds? @seconds > 0 end
def to_f
def to_f @original_seconds.to_f end
def to_s
def to_s format_smart end