Duration

Duration is a simple class that provides ways of easily manipulating durations (timespans) and formatting them as well.

    require 'duration'
    => true
    d = Duration.new(60 * 60 * 24 * 10 + 120 + 30)
    => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
    d.to_s
    => "1 week, 3 days, 2 minutes and 30 seconds"
    [d.weeks, d.days]
    => [1, 3]
    d.days = 7; d
    => #<Duration: 2 weeks, 2 minutes and 30 seconds>
    d.strftime('%w w, %d d, %h h, %m m, %s s')
    => "2 w, 0 d, 0 h, 2 m, 30 s"
Methods
Included Modules
Constants
WEEK = 60 * 60 * 24 * 7
DAY = 60 * 60 * 24
HOUR = 60 * 60
MINUTE = 60
SECOND = 1
Attributes
[R] days
[R] hours
[R] minutes
[R] total
[R] weeks
Public Class methods
new(seconds_or_attr = 0)

Initialize Duration class.

Example

    d = Duration.new(60 * 60 * 24 * 10 + 120 + 30)
    => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
    d = Duration.new(:weeks => 1, :days => 3, :minutes => 2, :seconds => 30)
    => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
# File lib/facets/duration.rb, line 71
    def initialize(seconds_or_attr = 0)
        if seconds_or_attr.kind_of? Hash
            # Part->time map table.
            h = {:weeks => WEEK, :days => DAY, :hours => HOUR, :minutes => MINUTE, :seconds => SECOND}

            # Loop through each valid part, ignore all others.
            seconds = seconds_or_attr.inject(0) do |sec, args|
                # Grab the part of the duration (week, day, whatever) and the number of seconds for it.
                part, time = args

                # Map each part to their number of seconds and the given value.
                # {:weeks => 2} maps to h[:weeks] -- so... weeks = WEEK * 2
                if h.key?(prt = part.to_s.to_sym) then sec + time * h[prt] else 0 end
            end
        else
            seconds = seconds_or_attr
        end

        @total, array = seconds.to_f.round, []
        @seconds = [WEEK, DAY, HOUR, MINUTE].inject(@total) do |left, part|
            array << left / part; left % part
        end

        @weeks, @days, @hours, @minutes = array
    end
Public Instance methods
*(other)

Multiply two Durations.

Example

    d = Duration.new(30)
    => #<Duration: 30 seconds>
    d * 2
    => #<Duration: 1 minute>
# File lib/facets/duration.rb, line 332
    def *(other)
        self.class.new(@total * other.to_i)
    end
+(other)

Add to Duration.

Example

    d = Duration.new(30)
    => #<Duration: 30 seconds>
    d + 30
    => #<Duration: 1 minute>
# File lib/facets/duration.rb, line 306
    def +(other)
        self.class.new(@total + other.to_i)
    end
-(other)

Subtract from Duration.

Example

    d = Duration.new(30)
    => #<Duration: 30 seconds>
    d - 15
    => #<Duration: 15 seconds>
# File lib/facets/duration.rb, line 319
    def -(other)
        self.class.new(@total - other.to_i)
    end
/(other)

Divide two Durations.

Example

    d = Duration.new(30)
    => #<Duration: 30 seconds>
    d / 2
    => #<Duration: 15 seconds>
# File lib/facets/duration.rb, line 345
    def /(other)
        self.class.new(@total / other.to_i)
    end
<=>(other)

Calls `<=>’ on Duration#total.

Example

    5.days == 24.hours * 5
    => true
# File lib/facets/duration.rb, line 194
    def <=>(other)
        @total <=> other.to_i
    end
days=(n)

Set the number of days.

Example

    d = Duration.new(0)
    => #<Duration: ...>
    d.days = 5; d
    => #<Duration: 5 days>
# File lib/facets/duration.rb, line 220
    def days=(n)
        initialize(:days => n, :seconds => @total - seconds(:days))
    end
each() {|part, time| ...}

For iterating through the duration set of weeks, days, hours, minutes, and seconds.

Example

    Duration.new(:weeks => 1, :seconds => 30).each do |part, time|
        puts "part: #{part}, time: #{time}"
    end

Output

    part: weeks, time: 1
    part: days, time: 0
    part: hours, time: 0
    part: minutes, time: 0
    part: seconds, time: 30
# File lib/facets/duration.rb, line 176
    def each
        [['weeks'   ,  @weeks  ],
         ['days'    ,  @days   ],
         ['hours'   ,  @hours  ],
         ['minutes' ,  @minutes],
         ['seconds' ,  @seconds]].each do |part, time|
             # Yield to block
            yield part, time
        end
    end
hours=(n)

Set the number of hours.

Example

    d = Duration.new(0)
    => #<Duration: ...>
    d.hours = 5; d
    => #<Duration: 5 hours>
# File lib/facets/duration.rb, line 233
    def hours=(n)
        initialize(:hours => n, :seconds => @total - seconds(:hours))
    end
inspect()

Inspection string—Similar to to_s except that it has the class name.

Example

    Duration.new(:seconds => 140)
    => #<Duration: 2 minutes and 20 seconds>
# File lib/facets/duration.rb, line 293
    def inspect
        "#<#{self.class}: #{(s = to_s).empty? ? '...' : s}>"
    end
minutes=(n)

Set the number of minutes.

Example

    d = Duration.new(0)
    => #<Duration: ...>
    d.minutes = 30; d
    => #<Duration: 30 minutes>
# File lib/facets/duration.rb, line 246
    def minutes=(n)
        initialize(:minutes => n, :seconds => @total - seconds(:minutes))
    end
seconds(part = nil)

Get the number of seconds of a given part, or simply just get the number of seconds.

Example

    d = Duration.new(:weeks => 1, :days => 1, :hours => 1, :seconds => 30)
    => #<Duration: 1 week, 1 day, 1 hour and 30 seconds>
    d.seconds(:weeks)
    => 604800
    d.seconds(:days)
    => 86400
    d.seconds(:hours)
    => 3600
    d.seconds
    => 30
# File lib/facets/duration.rb, line 148
    def seconds(part = nil)
        # Table mapping
        h = {:weeks => WEEK, :days => DAY, :hours => HOUR, :minutes => MINUTE}

        if [:weeks, :days, :hours, :minutes].include? part
            __send__(part) * h[part]
        else
            @seconds
        end
    end
seconds=(n)

Set the number of minutes.

Example

    d = Duration.new(0)
    => #<Duration: ...>
    d.seconds = 30; d
    => #<Duration: 30 seconds>
# File lib/facets/duration.rb, line 259
    def seconds=(n)
        initialize(:seconds => (@total + n) - @seconds)
    end
strftime(fmt)

Format duration.

Identifiers

    %w -- Number of weeks
    %d -- Number of days
    %h -- Number of hours
    %m -- Number of minutes
    %s -- Number of seconds
    %t -- Total number of seconds
    %x -- Duration#to_s
    %% -- Literal `%' character

Example

    d = Duration.new(:weeks => 10, :days => 7)
    => #<Duration: 11 weeks>
    d.strftime("It's been %w weeks!")
    => "It's been 11 weeks!"
# File lib/facets/duration.rb, line 117
    def strftime(fmt)
        h =\
        {'w' => @weeks  ,
         'd' => @days   ,
         'h' => @hours  ,
         'm' => @minutes,
         's' => @seconds,
         't' => @total  ,
         'x' => to_s}

        fmt.gsub(/%?%(w|d|h|m|s|t|x)/) do |match|
            match.size == 3 ? match : h[match[1..1]]
        end.gsub('%%', '%')
    end
to_s()

Friendly, human-readable string representation of the duration.

Example

    d = Duration.new(:seconds => 140)
    => #<Duration: 2 minutes and 20 seconds>
    d.to_s
    => "2 minutes and 20 seconds"
# File lib/facets/duration.rb, line 272
    def to_s
        str = ''

        each do |part, time|
            # Skip any zero times.
            next if time.zero?

            # Concatenate the part of the time and the time itself.
            str << "#{time} #{time == 1 ? part[0..-2] : part}, "
        end

        str.chomp(', ').sub(/(.+), (.+)/, '\1 and \2')
    end
weeks=(n)

Set the number of weeks.

Example

    d = Duration.new(0)
    => #<Duration: ...>
    d.weeks = 2; d
    => #<Duration: 2 weeks>
# File lib/facets/duration.rb, line 207
    def weeks=(n)
        initialize(:weeks => n, :seconds => @total - seconds(:weeks))
    end