Class: Timerizer::Duration

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/timerizer/duration.rb,
lib/timerizer/duration/rounded_time.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.

Defined Under Namespace

Classes: RoundedTime

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']
    }
  },
  min_long: {
    units: {
      seconds: ['second', 'seconds'],
      minutes: ['minute', 'minutes'],
      hours: ['hour', 'hours'],
      days: ['day', 'days'],
      months: ['month', 'months'],
      years: ['year', 'years']
    },
    count: 2
  }
}

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.



160
161
162
163
164
165
166
167
168
169
# File 'lib/timerizer/duration.rb', line 160

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.



527
528
529
530
531
532
533
534
535
536
537
# File 'lib/timerizer/duration.rb', line 527

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:



479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
# File 'lib/timerizer/duration.rb', line 479

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.



504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/timerizer/duration.rb', line 504

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.



453
454
455
# File 'lib/timerizer/duration.rb', line 453

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.



553
554
555
556
557
558
559
560
561
562
563
# File 'lib/timerizer/duration.rb', line 553

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`.



441
442
443
444
445
446
447
448
# File 'lib/timerizer/duration.rb', line 441

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:



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/timerizer/duration.rb', line 234

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:



217
218
219
# File 'lib/timerizer/duration.rb', line 217

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:



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

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.



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/timerizer/duration.rb', line 410

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:



265
266
267
# File 'lib/timerizer/duration.rb', line 265

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:



184
185
186
187
188
189
190
191
192
# File 'lib/timerizer/duration.rb', line 184

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:



370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
# File 'lib/timerizer/duration.rb', line 370

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

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:



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

self.define_to_unit(:months)

#to_rounded_s(format = :min_long, options = nil) ⇒ String

Convert a Duration to a human-readable string using a rounded value.

By ‘rounded’, we mean that the resulting value is rounded up if the input includes a value of more than half of one of the least-significant unit to be returned. For example, ‘(17.hours 43.minutes 31.seconds)`, when rounded to two units (hours and minutes), would return “17 hours, 44 minutes”. By contrast, `#to_s`, with a `:count` option of 2, would return a value of “17 hours, 43 minutes”: truncating, rather than rounding.

Note that this method overloads the meaning of the ‘:count` option value as documented below. If the passed-in option value is numeric, it will be honored, and rounding will take place to that number of units. If the value is either `:all` or the default `nil`, then rounding will be done to two units, and the rounded value will be passed on to `#to_s` with the options specified (which will result in a maximum of two time units being output).

Parameters:

  • format (Symbol, Hash) (defaults to: :min_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`. The default is `:min_long`, which strongly resembles `:long` with the omission of `:weeks` units and a default `:count` of 2.

  • 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 rounded duration formatted as a string.



701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
# File 'lib/timerizer/duration.rb', line 701

def to_rounded_s(format = :min_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(Hash(options))
  places = format[:count]
  begin
    places = Integer(places) # raise if nil or `:all` supplied as value
  rescue TypeError
    places = 2
  end
  q = RoundedTime.call(self, places)
  q.to_s(format, options)
end

#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.



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
644
645
646
647
648
649
650
651
652
653
# File 'lib/timerizer/duration.rb', line 606

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] || ' '
  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:



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

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:



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

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:



293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/timerizer/duration.rb', line 293

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.



333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/timerizer/duration.rb', line 333

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:



572
573
574
575
# File 'lib/timerizer/duration.rb', line 572

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:



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

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:



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

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:



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

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:



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

self.define_to_unit(:years)