Module: IS::Duration

Defined in:
lib/is-duration/info.rb,
lib/is-duration.rb

Defined Under Namespace

Classes: OnEmpty, OnMinus, OnZero, Unit

Singleton Interface collapse

Include Interface collapse

Class Method Details

.format(value, **opts) ⇒ String?

Parameters:

  • value (Numeric, nil)

    Integer or Float, Rational will be converted to Float

  • opts (Hash)

Options Hash (**opts):

  • units (Range<Unit|Symbol>)

    default: (Unit.s .. Unit.d)

  • empty (OnEmpty|Symbol)

    default: OnEmpty.skip

  • zeros (OnZero|Symbol)

    default: OnZero.single

  • delim (String)

    “” (empty string), “ ” (space) or other, default: “”

  • minus (OnMinus|Symbol|String|Proc)

    default: OnMinus.ignore

Returns:

  • (String, nil)

Raises:

  • (ArgumentError)


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/is-duration.rb', line 72

def format value, **opts
  return nil if value.nil?
  value = value.to_f if value.is_a?(Rational)
  raise ArgumentError, "Invalid source value: #{ value.inspect }", caller_locations unless value.is_a?(Integer) || value.is_a?(Float)
  units = Unit::from(opts[:units] || (:s .. :d))
  empty = OnEmpty::from(opts[:empty] || :skip)
  zeros = OnZero::from(opts[:zeros] || :single)
  delim = opts[:delim] || ''
  minus = case opts[:minus]
  when OnMinus, String, Proc
    opts[:minus]
  when Symbol
    OnMinus[opts[:minus]]
  when nil
    OnMinus.ignore
  else
    raise ArgumentError, "Invalid option 'minus': #{ opts.minus }", caller_locations
  end
  sgn = value <=> 0
  raise ArgumentError, "Invalid source value: #{ value.inspect }", caller_locations if sgn < 0 && minus == OnMinus::error
  abs = value.abs
  int, frac = abs.divmod 1
  weeks = days = hours = minutes = seconds = 0
  if units.end > Unit::s && int > 60
    min, seconds = int.divmod 60
    if units.end > Unit::m && min > 60
      hrs, minutes = min.divmod 60
      if units.end > Unit::h && hrs > 24
        dys, hours = hrs.divmod 24
        if units.end > Unit::d && dys > 7
          weeks, days = dys.divmod 7
        else
          days = dys
        end
      else
        hours = hrs
      end
    else
      minutes = min
    end
  else
    seconds = int
  end
  nanoseconds = microseconds = milliseconds = 0
  if units.begin < Unit::s
    str_frac = Kernel::format('%.9f', frac)[-9..]
    str_ms, str_us, str_ns = str_frac[0, 3], str_frac[3, 3], str_frac[6, 3]
    milliseconds, microseconds, nanoseconds = str_ms.to_i, str_us.to_i, str_ns.to_i
  end
  if units.end < Unit::us
    nanoseconds += seconds * 1_000_000_000
    nanoseconds += milliseconds * 1_000_000
    nanoseconds += microseconds * 1_000
    seconds = milliseconds = microseconds = 0
  elsif units.end < Unit::ms
    microseconds += seconds * 1_000_000
    microseconds += milliseconds * 1_000
    seconds = milliseconds = 0
  elsif units.end < Unit::s
    milliseconds += seconds * 1_000
    seconds = 0
  end
  map = {
    Unit::w => weeks,
    Unit::d => days,
    Unit::h => hours,
    Unit::m => minutes,
    Unit::s => seconds,
    Unit::ms => milliseconds,
    Unit::us => microseconds,
    Unit::ns => nanoseconds
  }
  units_array = units.to_a.reverse
  fmt2 = case zeros
  when OnZero::fill
    '%02d'
  when OnZero::align
    '%2d'
  else
    '%d'
  end
  fmt3 = case zeros
  when OnZero::fill
    '%03d'
  when OnZero::align
    '%3d'
  else
    '%d'
  end
  result = []
  started = false
  units_array.each do |u|
    value = map[u]
    next if value == 0 && (empty == OnEmpty::skip || (empty == OnEmpty::minor && !started))
    first = true if !started
    started = true
    fmt = if first 
      '%d'
    elsif Unit::from(:s..:h) === u
      fmt2
    elsif Unit::from(:ns..:ms) === u
      fmt3
    else
      '%d'
    end
    item = Kernel::format fmt, value
    result << item + u.to_s
    first = false
  end
  result = result.join(delim).strip
  if sgn < 0
    case minus
    when Proc
      result = minus[result]
    when String
      result = minus + delim + result
    end
  end
  result
end

.parse(source) ⇒ Numeric?

Parameters:

  • source (String, nil)

Returns:

  • (Numeric, nil)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/is-duration.rb', line 43

def parse source
  case source
  when nil
    nil
  when Integer, Float
    source
  when Rational
    source.to_f
  when /^\d+$/
    source.to_i
  when /^\d*\.\d*$/
    source.to_f
  when /^(\d+(w|d|h|m|s|ms|us|ns)\s*)+$/
    parse_string source
  else
    raise ArgumentError, "Invalid source value: #{ source.inspect }", caller_locations
  end
end

Instance Method Details

#format_duration(value, **opts) ⇒ String? (private)

Returns:

  • (String, nil)

See Also:



244
245
246
# File 'lib/is-duration.rb', line 244

def format_duration value, **opts
  IS::Duration.format(value, **opts)
end

#parse_duration(source) ⇒ Numeric? (private)

Parameters:

  • source (String, nil)

Returns:

  • (Numeric, nil)

See Also:



240
# File 'lib/is-duration.rb', line 240

def parse_duration(source) = IS::Duration.parse(source)