Provides accurate date and time measurements using Date#advance
and Time#advance
, respectively. It mainly supports the methods on Numeric
.
1.month.ago # equivalent to Time.now.advance(months: -1)
# File activesupport/lib/active_support/duration.rb, line 188 def build(value) unless value.is_a?(::Numeric) raise TypeError, "can't build an #{self.name} from a #{value.class.name}" end parts = {} remainder_sign = value <=> 0 remainder = value.round(9).abs variable = false PARTS.each do |part| unless part == :seconds part_in_seconds = PARTS_IN_SECONDS[part] parts[part] = remainder.div(part_in_seconds) * remainder_sign remainder %= part_in_seconds unless parts[part].zero? variable ||= VARIABLE_PARTS.include?(part) end end end unless value == 0 parts[:seconds] = remainder * remainder_sign new(value, parts, variable) end
Creates a new Duration
from a seconds value that is converted to the individual parts:
ActiveSupport::Duration.build(31556952).parts # => {:years=>1} ActiveSupport::Duration.build(2716146).parts # => {:months=>1, :days=>1}
# File activesupport/lib/active_support/duration.rb, line 143 def parse(iso8601duration) parts = ISO8601Parser.new(iso8601duration).parse! new(calculate_total_seconds(parts), parts) end
Creates a new Duration
from string formatted according to ISO 8601 Duration
.
See ISO 8601 for more information. This method allows negative parts to be present in pattern. If invalid string is provided, it will raise ActiveSupport::Duration::ISO8601Parser::ParsingError
.
# File activesupport/lib/active_support/duration.rb, line 306 def %(other) if Duration === other || Scalar === other Duration.build(value % other.value) elsif Numeric === other Duration.build(value % other) else raise_type_error(other) end end
Returns the modulo of this Duration
by another Duration
or Numeric
. Numeric
values are treated as seconds.
# File activesupport/lib/active_support/duration.rb, line 281 def *(other) if Scalar === other || Duration === other Duration.new(value * other.value, @parts.transform_values { |number| number * other.value }, @variable || other.variable?) elsif Numeric === other Duration.new(value * other, @parts.transform_values { |number| number * other }, @variable) else raise_type_error(other) end end
Multiplies this Duration
by a Numeric
and returns a new Duration
.
# File activesupport/lib/active_support/duration.rb, line 262 def +(other) if Duration === other parts = @parts.merge(other._parts) do |_key, value, other_value| value + other_value end Duration.new(value + other.value, parts, @variable || other.variable?) else seconds = @parts.fetch(:seconds, 0) + other Duration.new(value + other, @parts.merge(seconds: seconds), @variable) end end
Adds another Duration
or a Numeric
to this Duration
. Numeric
values are treated as seconds.
# File activesupport/lib/active_support/duration.rb, line 292 def /(other) if Scalar === other Duration.new(value / other.value, @parts.transform_values { |number| number / other.value }, @variable) elsif Duration === other value / other.value elsif Numeric === other Duration.new(value / other, @parts.transform_values { |number| number / other }, @variable) else raise_type_error(other) end end
Divides this Duration
by a Numeric
and returns a new Duration
.
# File activesupport/lib/active_support/duration.rb, line 335 def ==(other) if Duration === other other.value == value else other == value end end
Returns true
if other
is also a Duration
instance with the same value
, or if other == value
.
# File activesupport/lib/active_support/duration.rb, line 420 def eql?(other) Duration === other && other.value.eql?(value) end
Returns true
if other
is also a Duration
instance, which has the same parts as this one.
# File activesupport/lib/active_support/duration.rb, line 424 def hash @value.hash end
# File activesupport/lib/active_support/duration.rb, line 393 def in_days in_seconds / SECONDS_PER_DAY.to_f end
Returns the amount of days a duration covers as a float
12.hours.in_days # => 0.5
# File activesupport/lib/active_support/duration.rb, line 386 def in_hours in_seconds / SECONDS_PER_HOUR.to_f end
Returns the amount of hours a duration covers as a float
1.day.in_hours # => 24.0
# File activesupport/lib/active_support/duration.rb, line 379 def in_minutes in_seconds / SECONDS_PER_MINUTE.to_f end
Returns the amount of minutes a duration covers as a float
1.day.in_minutes # => 1440.0
# File activesupport/lib/active_support/duration.rb, line 407 def in_months in_seconds / SECONDS_PER_MONTH.to_f end
Returns the amount of months a duration covers as a float
9.weeks.in_months # => 2.07
# File activesupport/lib/active_support/duration.rb, line 400 def in_weeks in_seconds / SECONDS_PER_WEEK.to_f end
Returns the amount of weeks a duration covers as a float
2.months.in_weeks # => 8.696
# File activesupport/lib/active_support/duration.rb, line 414 def in_years in_seconds / SECONDS_PER_YEAR.to_f end
Returns the amount of years a duration covers as a float
30.days.in_years # => 0.082
# File activesupport/lib/active_support/duration.rb, line 467 def iso8601(precision: nil) ISO8601Serializer.new(self, precision: precision).serialize end
Build ISO 8601 Duration
string for this duration. The precision
parameter can be used to limit seconds' precision of duration.
# File activesupport/lib/active_support/duration.rb, line 235 def parts @parts.dup end
Returns a copy of the parts hash that defines the duration
# File activesupport/lib/active_support/duration.rb, line 371 def to_i @value.to_i end
Returns the number of seconds that this Duration
represents.
1.minute.to_i # => 60 1.hour.to_i # => 3600 1.day.to_i # => 86400
Note that this conversion makes some assumptions about the duration of some periods, e.g. months are always 1/12 of year and years are 365.2425 days:
# equivalent to (1.year / 12).to_i 1.month.to_i # => 2629746 # equivalent to 365.2425.days.to_i 1.year.to_i # => 31556952
In such cases, Ruby's core Date and Time should be used for precision date and time arithmetic.
# File activesupport/lib/active_support/duration.rb, line 347 def to_s @value.to_s end
Returns the amount of seconds a duration covers as a string. For more information check to_i
method.
1.day.to_s # => "86400"
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.