Class: Timerizer::Duration

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/timerizer/duration.rb

Overview

Represents a duration of time. For example, ‘5 days’, ‘4 years’, and ‘5 years, 4 hours, 3 minutes, 2 seconds’ are all durations conceptually.

A ‘Duration` is made up of two different primitive units: seconds and months. The philosphy behind this is this: every duration of time can be broken down into these fundamental pieces, but cannot be simplified further. For example, 1 year always equals 12 months, 1 minute always equals 60 seconds, but 1 month does not always equal 30 days. This ignores some important corner cases (such as leap seconds), but this philosophy should be “good enough” for most use-cases.

This extra divide between “seconds” and “months” may seem useless or conter-intuitive at first, but can be useful when applying durations to times. For example, ‘1.year.after(Time.new(2000, 1, 1))` is guaranteed to return `Time.new(2001, 1, 1)`, which would not be possible if all durations were represented in seconds alone.

On top of that, even though 1 month cannot be exactly represented as a certain number of days, it’s still useful to often convert between durations made of different base units, especially when converting a ‘Duration` to a human-readable format. This is the reason for the #normalize and #denormalize methods. For convenience, most methods perform normalization on the input duration, so that some results or comparisons give more intuitive values.

Constant Summary collapse

UNITS =

A hash describing the different base units of a ‘Duration`. Key represent unit names and values represent a hash describing the scale of that unit.

{
  seconds: {seconds: 1},
  minutes: {seconds: 60},
  hours: {seconds: 60 * 60},
  days: {seconds: 24 * 60 * 60},
  weeks: {seconds: 7 * 24 * 60 * 60},
  months: {months: 1},
  years: {months: 12},
  decades: {months: 12 * 10},
  centuries: {months: 12 * 100},
  millennia: {months: 12 * 1000}
}
UNIT_ALIASES =

A hash describing different names for various units, which allows for, e.g., pluralized unit names, or more obscure units. ‘UNIT_ALIASES` is guaranteed to also contain all of the entries from UNITS.

UNITS.merge(
  second: UNITS[:seconds],
  minute: UNITS[:minutes],
  hour: UNITS[:hours],
  day: UNITS[:days],
  week: UNITS[:weeks],
  month: UNITS[:months],
  year: UNITS[:years],
  decade: UNITS[:decades],
  century: UNITS[:centuries],
  millennium: UNITS[:millennia]
)
NORMALIZATION_METHODS =

The built-in set of normalization methods, usable with #normalize and #denormalize. Keys are method names, and values are hashes describing how units are normalized or denormalized.

The following normalization methods are defined:

  • ‘:standard`: 1 month is approximated as 30 days, and 1 year is approximated as 365 days.

  • ‘:minimum`: 1 month is approximated as 28 days (the minimum in any month), and 1 year is approximated as 365 days (the minimum in any year).

  • ‘:maximum`: 1 month is approximated as 31 days (the maximum in any month), and 1 year is approximated as 366 days (the maximum in any year).

{
  standard: {
    months: {seconds: 30 * 24 * 60 * 60},
    years: {seconds: 365 * 24 * 60 * 60}
  },
  minimum: {
    months: {seconds: 28 * 24 * 60 * 60},
    years: {seconds: 365 * 24 * 60 * 60}
  },
  maximum: {
    months: {seconds: 31 * 24 * 60 * 60},
    years: {seconds: 366 * 24 * 60 * 60}
  }
}
FORMATS =

The built-in formats that can be used with #to_s.

The following string formats are defined:

  • ‘:long`: The default, long-form string format. Example string: `“1 year, 2 months, 3 weeks, 4 days, 5 hours”`.

  • ‘:short`: A shorter format, which includes 2 significant units by default. Example string: `“1mo 2d”`

  • ‘:micro`: A very terse format, which includes only one significant unit by default. Example string: `“1h”`

{
  micro: {
    units: {
      seconds: 's',
      minutes: 'm',
      hours: 'h',
      days: 'd',
      weeks: 'w',
      months: 'mo',
      years: 'y',
    },
    separator: '',
    delimiter: ' ',
    count: 1
  },
  short: {
    units: {
      seconds: 'sec',
      minutes: 'min',
      hours: 'hr',
      days: 'd',
      weeks: 'wk',
      months: 'mo',
      years: 'yr'
    },
    separator: '',
    delimiter: ' ',
    count: 2
  },
  long: {
    units: {
      seconds: ['second', 'seconds'],
      minutes: ['minute', 'minutes'],
      hours: ['hour', 'hours'],
      days: ['day', 'days'],
      weeks: ['week', 'weeks'],
      months: ['month', 'months'],
      years: ['year', 'years']
    }
  }
}

Instance Method Summary collapse

Constructor Details

#initialize(units = {}) ⇒ Duration

Initialize a new instance of Timerizer::Duration.

Examples:

Timerizer::Duration.new(years: 4, months: 2, hours: 12, minutes: 60)

Parameters:

  • units (Hash<Symbol, Integer>) (defaults to: {})

    A hash that maps from unit names to the quantity of that unit. See the keys of UNIT_ALIASES for a list of valid unit names.



149
150
151
152
153
154
155
156
157
158
# File 'lib/timerizer/duration.rb', line 149

def initialize(units = {})
  @seconds = 0
  @months = 0

  units.each do |unit, n|
    unit_info = self.class.resolve_unit(unit)
    @seconds += n * unit_info.fetch(:seconds, 0)
    @months += n * unit_info.fetch(:months, 0)
  end
end

Instance Method Details

#*(other) ⇒ Duration

Multiply a duration by a scalar.

Examples:

1.day * 7 == 1.week

Parameters:

  • other (Integer)

    The scalar to multiply by.

Returns:

  • (Duration)

    The resulting duration with each component multiplied by the scalar.



516
517
518
519
520
521
522
523
524
525
526
# File 'lib/timerizer/duration.rb', line 516

def *(other)
  case other
  when Integer
    Duration.new(
      seconds: @seconds * other,
      months: @months * other
    )
  else
    raise ArgumentError, "Cannot multiply Duration #{self} by #{other.inspect}"
  end
end

#+(duration) ⇒ Duration #+(time) ⇒ Time

Overloads:

  • #+(duration) ⇒ Duration

    Add together two durations.

    Examples:

    1.day + 1.hour == 25.hours

    Parameters:

    • duration (Duration)

      The duration to add.

    Returns:

    • (Duration)

      The resulting duration with each component added to the input duration.

  • #+(time) ⇒ Time

    Add a time to a duration, returning a new time.

    Examples:

    1.day + Time.new(2000, 1, 1) == Time.new(2000, 1, 2)

    Parameters:

    • time (Time)

      The time to add this duration to.

    Returns:

    • (Time)

      The time after the duration has elapsed.

    See Also:



468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/timerizer/duration.rb', line 468

def +(other)
  case other
  when 0
    self
  when Duration
    Duration.new(
      seconds: @seconds + other.get(:seconds),
      months: @months + other.get(:months)
    )
  when Time
    self.after(other)
  else
    raise ArgumentError, "Cannot add #{other.inspect} to Duration #{self}"
  end
end

#-(other) ⇒ Duration

Subtract two durations.

Examples:

1.day - 1.hour == 23.hours

Parameters:

  • other (Duration)

    The duration to subtract.

Returns:

  • (Duration)

    The resulting duration with each component subtracted from the input duration.



493
494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/timerizer/duration.rb', line 493

def -(other)
  case other
  when 0
    self
  when Duration
    Duration.new(
      seconds: @seconds - other.get(:seconds),
      months: @months - other.get(:months)
    )
  else
    raise ArgumentError, "Cannot subtract #{other.inspect} from Duration #{self}"
  end
end

#-@Duration

Negates a duration.

Returns:

  • (Duration)

    A new duration where each component was negated.



442
443
444
# File 'lib/timerizer/duration.rb', line 442

def -@
  Duration.new(seconds: -@seconds, months: -@months)
end

#/(other) ⇒ Duration

Note:

A duration can only be divided by an integer divisor. The resulting duration will have each component divided with integer division, which will result in truncation.

Divide a duration by a scalar.

Examples:

1.week / 7 == 1.day
1.second / 2 == 0.seconds # This is a result of truncation

Parameters:

  • other (Integer)

    The scalar to divide by.

Returns:

  • (Duration)

    The resulting duration with each component divided by the scalar.



542
543
544
545
546
547
548
549
550
551
552
# File 'lib/timerizer/duration.rb', line 542

def /(other)
  case other
  when Integer
    Duration.new(
      seconds: @seconds / other,
      months: @months / other
    )
  else
    raise ArgumentError, "Cannot divide Duration #{self} by #{other.inspect}"
  end
end

#<=>(other) ⇒ Integer?

Compare two duartions. Note that durations are compared after normalization.

Parameters:

  • other (Duration)

    The duration to compare.

Returns:

  • (Integer, nil)

    0 if the durations are equal, -1 if the left-hand side is greater, +1 if the right-hand side is greater. Returns ‘nil` if the duration cannot be compared ot `other`.



430
431
432
433
434
435
436
437
# File 'lib/timerizer/duration.rb', line 430

def <=>(other)
  case other
  when Duration
    self.to_unit(:seconds) <=> other.to_unit(:seconds)
  else
    nil
  end
end

#after(time) ⇒ Time

Returns the time ‘self` later than the given time.

Examples:

5 minutes after January 1st, 2000 at noon

5.minutes.after(Time.new(2000, 1, 1, 12, 00, 00))
# => 2000-01-01 12:05:00 -0800

Parameters:

  • time (Time)

    The initial time.

Returns:

See Also:



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/timerizer/duration.rb', line 223

def after(time)
  time = time.to_time

  prev_day = time.mday
  prev_month = time.month
  prev_year = time.year

  units = self.to_units(:years, :months, :days, :seconds)

  date_in_month = self.class.build_date(
    prev_year + units[:years],
    prev_month + units[:months],
    prev_day
  )
  date = date_in_month + units[:days]

  Time.new(
    date.year,
    date.month,
    date.day,
    time.hour,
    time.min,
    time.sec
  ) + units[:seconds]
end

#agoTime

Return the time ‘self` later than the current time.

Returns:

See Also:



206
207
208
# File 'lib/timerizer/duration.rb', line 206

def ago
  self.before(Time.now)
end

#before(time) ⇒ Time

Returns the time ‘self` earlier than the given time.

Examples:

5 minutes before January 1st, 2000 at noon

5.minutes.before(Time.new(2000, 1, 1, 12, 00, 00))
# => 2000-01-01 11:55:00 -0800

Parameters:

  • time (Time)

    The initial time.

Returns:

See Also:



196
197
198
# File 'lib/timerizer/duration.rb', line 196

def before(time)
  (-self).after(time)
end

#denormalize(method: :standard) ⇒ Duration

Return a new duration that inverts an approximation made by #normalize. Denormalization results in a Timerizer::Duration where “second-based” units are converted back to “month-based” units. Note that, due to the lossy nature #normalize, the result of calling #normalize then #denormalize may result in a Timerizer::Duration that is not equal to the input.

Examples:

30.days.denormalize == 1.month
30.days.denormalize(method: :standard) == 1.month
28.days.denormalize(method: :minimum) == 1.month
31.days.denormalize(method: :maximum) == 1.month

365.days.denormalize == 1.year
365.days.denormalize(method: :standard) == 1.year
365.days.denormalize(method: :minimum) == 1.year
366.days.denormalize(method: :maximum) == 1.year

Parameters:

  • method (Symbol) (defaults to: :standard)

    The normalization method to invert. For a list of normalization methods, see NORMALIZATION_METHODS.

Returns:

  • (Duration)

    The duration after being denormalized.



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'lib/timerizer/duration.rb', line 399

def denormalize(method: :standard)
  normalized_units = NORMALIZATION_METHODS.fetch(method).reverse_each

  initial = [0.seconds, self]
  result = normalized_units.reduce(initial) do |result, (unit, normal)|
    denormalized, remainder = result

    seconds_per_unit = normal.fetch(:seconds)
    remainder_seconds = remainder.get(:seconds)

    num_unit = self.class.div(remainder_seconds, seconds_per_unit)
    num_seconds_denormalized = num_unit * seconds_per_unit

    denormalized += Duration.new(unit => num_unit)
    remainder -= num_seconds_denormalized.seconds

    [denormalized, remainder]
  end

  denormalized, remainder = result
  denormalized + remainder
end

#from_nowTime

Return the time ‘self` earlier than the current time.

Returns:

See Also:



254
255
256
# File 'lib/timerizer/duration.rb', line 254

def from_now
  self.after(Time.now)
end

#get(unit) ⇒ Integer

Return the number of “base” units in a Timerizer::Duration. Note that this method is a lower-level method, and will not be needed by most users. See #to_unit for a more general equivalent.

Parameters:

  • unit (Symbol)

    The base unit to return, either ‘:seconds` or `:months`.

Returns:

  • (Integer)

    The requested unit count. Note that this method does not perform normalization first, so results may not be intuitive.

Raises:

  • (ArgumentError)

    The unit requested was not ‘:seconds` or `:months`.

See Also:



173
174
175
176
177
178
179
180
181
# File 'lib/timerizer/duration.rb', line 173

def get(unit)
  if unit == :seconds
    @seconds
  elsif unit == :months
    @months
  else
    raise ArgumentError
  end
end

#normalize(method: :standard) ⇒ Duration

Return a new duration that approximates the given input duration, where every “month-based” unit of the input is converted to seconds. Because durations are composed of two distinct units (“seconds” and “months”), two durations need to be normalized before being compared. By default, most methods on Timerizer::Duration perform normalization or denormalization, so clients will not usually need to call this method directly.

Examples:

1.month.normalize == 30.days
1.month.normalize(method: :standard) == 30.days
1.month.normalize(method: :maximum) == 31.days
1.month.normalize(method: :minimum) == 28.days

1.year.normalize == 365.days
1.year.normalize(method: :standard) == 365.days
1.year.normalize(method: :minimum) == 365.days
1.year.normalize(method: :maximum) == 366.days

Parameters:

  • method (Symbol) (defaults to: :standard)

    The normalization method to be used. For a list of normalization methods, see NORMALIZATION_METHODS.

Returns:

  • (Duration)

    The duration after being normalized.

See Also:



359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/timerizer/duration.rb', line 359

def normalize(method: :standard)
  normalized_units = NORMALIZATION_METHODS.fetch(method).reverse_each

  initial = [0.seconds, self]
  result = normalized_units.reduce(initial) do |result, (unit, normal)|
    normalized, remainder = result

    seconds_per_unit = normal.fetch(:seconds)
    unit_part = remainder.send(:to_unit_part, unit)

    normalized += (unit_part * seconds_per_unit).seconds
    remainder -= Duration.new(unit => unit_part)
    [normalized, remainder]
  end

  normalized, remainder = result
  normalized + remainder
end

#to_centuriesInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:centuries`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



753
# File 'lib/timerizer/duration.rb', line 753

self.define_to_unit(:centuries)

#to_centuryInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:century`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



763
# File 'lib/timerizer/duration.rb', line 763

self.define_to_unit(:century)

#to_dayInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:day`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



758
# File 'lib/timerizer/duration.rb', line 758

self.define_to_unit(:day)

#to_daysInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:days`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



748
# File 'lib/timerizer/duration.rb', line 748

self.define_to_unit(:days)

#to_decadeInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:decade`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



762
# File 'lib/timerizer/duration.rb', line 762

self.define_to_unit(:decade)

#to_decadesInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:decades`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



752
# File 'lib/timerizer/duration.rb', line 752

self.define_to_unit(:decades)

#to_hourInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:hour`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



757
# File 'lib/timerizer/duration.rb', line 757

self.define_to_unit(:hour)

#to_hoursInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:hours`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



747
# File 'lib/timerizer/duration.rb', line 747

self.define_to_unit(:hours)

#to_millenniaInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:millennia`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



754
# File 'lib/timerizer/duration.rb', line 754

self.define_to_unit(:millennia)

#to_millenniumInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:millennium`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



764
# File 'lib/timerizer/duration.rb', line 764

self.define_to_unit(:millennium)

#to_minuteInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:minute`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



756
# File 'lib/timerizer/duration.rb', line 756

self.define_to_unit(:minute)

#to_minutesInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:minutes`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



746
# File 'lib/timerizer/duration.rb', line 746

self.define_to_unit(:minutes)

#to_monthInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:month`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



760
# File 'lib/timerizer/duration.rb', line 760

self.define_to_unit(:month)

#to_monthsInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:months`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



750
# File 'lib/timerizer/duration.rb', line 750

self.define_to_unit(:months)

#to_s(format = :long, options = nil) ⇒ String

Convert a duration to a human-readable string.

Parameters:

  • format (Symbol, Hash) (defaults to: :long)

    The format type to format the duration with. ‘format` can either be a key from the FORMATS hash or a hash with the same shape as `options`.

  • options (Hash, nil) (defaults to: nil)

    Additional options to use to override default format options.

Options Hash (options):

  • :units (Hash<Symbol, String>)

    The full list of unit names to use. Keys are unit names (see UNIT_ALIASES for a full list) and values are strings to use when converting that unit to a string. Values can also be an array, where the first item of the array will be used for singular unit names and the second item will be used for plural unit names. Note that this option will completely override the input formats’ list of names, so all units that should be used must be specified!

  • :separator (String)

    The separator to use between a unit quantity and the unit’s name. For example, the string ‘“1 second”` uses a separator of `“ ”`.

  • :delimiter (String)

    The delimiter to use between separate units. For example, the string ‘“1 minute, 1 second”` uses a separator of `“, ”`

  • :count (Integer, nil, :all)

    The number of significant units to use in the string, or ‘nil` / `:all` to use all units. For example, if the given duration is `1.day 1.week 1.month`, and `options` is 2, then the resulting string will only include the month and the week components of the string.

Returns:

  • (String)

    The duration formatted as a string.



595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
# File 'lib/timerizer/duration.rb', line 595

def to_s(format = :long, options = nil)
  format =
    case format
    when Symbol
      FORMATS.fetch(format)
    when Hash
      FORMATS.fetch(:long).merge(format)
    else
      raise ArgumentError, "Expected #{format.inspect} to be a Symbol or Hash"
    end

  format = format.merge(options || {})

  count =
    if format[:count].nil? || format[:count] == :all
      UNITS.count
    else
      format[:count]
    end

  format_units = format.fetch(:units)
  units = self.to_units(*format_units.keys).select {|unit, n| n > 0}
  if units.empty?
    units = {seconds: 0}
  end

  separator = format[:separator] || ' '
  delimiter = format[:delimiter] || ', '
  units.take(count).map do |unit, n|
    unit_label = format_units.fetch(unit)

    singular, plural =
      case unit_label
      when Array
        unit_label
      else
        [unit_label, unit_label]
      end

      unit_name =
        if n == 1
          singular
        else
          plural || singular
        end

      [n, unit_name].join(separator)
  end.join(format[:delimiter] || ', ')
end

#to_secondInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:second`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



755
# File 'lib/timerizer/duration.rb', line 755

self.define_to_unit(:second)

#to_secondsInteger

NOTE: We need to manually spell out each unit with ‘define_to_unit` to get proper documentation for each method. To ensure that we don’t miss any units, there’s a test in ‘duration_spec.rb` to ensure each of these methods actually exist. Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with `:seconds`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



745
# File 'lib/timerizer/duration.rb', line 745

self.define_to_unit(:seconds)

#to_unit(unit) ⇒ Integer

Note:

The duration is normalized or denormalized first, depending on the unit requested. This means that, by default, the returned unit will be an approximation if it cannot be represented exactly by the duration, such as when converting a duration of months to seconds, or vice versa.

Convert the duration to a given unit.

Examples:

1.hour.to_unit(:minutes)
# => 60
121.seconds.to_unit(:minutes)
# => 2

Parameters:

  • unit (Symbol)

    The unit to convert to. See UNIT_ALIASES for a list of valid unit names.

Returns:

  • (Integer)

    The quantity of the given unit present in ‘self`. Note that, if `self` cannot be represented exactly by `unit`, then the result will be truncated (rounded toward 0 instead of rounding down, unlike normal Ruby integer division).

Raises:

  • ArgumentError if the given unit could not be resolved.

See Also:



282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/timerizer/duration.rb', line 282

def to_unit(unit)
  unit_details = self.class.resolve_unit(unit)

  if unit_details.has_key?(:seconds)
    seconds = self.normalize.get(:seconds)
    self.class.div(seconds, unit_details.fetch(:seconds))
  elsif unit_details.has_key?(:months)
    months = self.denormalize.get(:months)
    self.class.div(months, unit_details.fetch(:months))
  else
    raise "Unit should have key :seconds or :months"
  end
end

#to_units(*units) ⇒ Hash<Symbol, Integer>

Note:

The duration may be normalized or denormalized first, depending on the units requested. This behavior is identical to #to_unit.

Convert the duration to a hash of units. For each given unit argument, the returned hash will map the unit to the quantity of that unit present in the duration. Each returned unit will be truncated to an integer, and the remainder will “carry” to the next unit down. The resulting hash can be passed to #initialize to get the same result, so this method can be thought of as the inverse of #initialize.

Examples:

121.seconds.to_units(:minutes)
# => {minutes: 2}
121.seconds.to_units(:minutes, :seconds)
# => {minutes: 2, seconds: 1}
1.year.to_units(:days)
# => {days: 365}
(91.days 12.hours).to_units(:months, :hours)
# => {months: 3, hours: 36}

Parameters:

  • units (Array<Symbol>)

    The units to convert to. Each unit will correspond with a key in the returned hash.

Returns:

  • (Hash<Symbol, Integer>)

    A hash mapping each unit to the quantity of that unit. Note that whether the returned unit is plural, or uses an alias, depends on what unit was passed in as an argument.



322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/timerizer/duration.rb', line 322

def to_units(*units)
  sorted_units = self.class.sort_units(units).reverse

  _, parts = sorted_units.reduce([self, {}]) do |(remainder, parts), unit|
    part = remainder.to_unit(unit)
    new_remainder = remainder - Duration.new(unit => part)

    [new_remainder, parts.merge(unit => part)]
  end

  parts
end

#to_wallWallClock

Convert a duration to a WallClock.

Examples:

(17.hours 30.minutes).to_wall
# => 5:30:00 PM

Returns:

Raises:



561
562
563
564
# File 'lib/timerizer/duration.rb', line 561

def to_wall
  raise WallClock::TimeOutOfBoundsError if @months > 0
  WallClock.new(second: @seconds)
end

#to_weekInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:week`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



759
# File 'lib/timerizer/duration.rb', line 759

self.define_to_unit(:week)

#to_weeksInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:weeks`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



749
# File 'lib/timerizer/duration.rb', line 749

self.define_to_unit(:weeks)

#to_yearInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:year`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



761
# File 'lib/timerizer/duration.rb', line 761

self.define_to_unit(:year)

#to_yearsInteger

Convert the duration to the given unit. This is a helper that is equivalent to calling #to_unit with ‘:years`.

Returns:

  • (Integer)

    the quantity of the unit in the duration.

See Also:



751
# File 'lib/timerizer/duration.rb', line 751

self.define_to_unit(:years)