Class: ActiveSupport::Duration
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Inherits: | Object |
Defined in: | activesupport/lib/active_support/duration.rb, activesupport/lib/active_support/duration/iso8601_parser.rb, activesupport/lib/active_support/duration/iso8601_serializer.rb |
Overview
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)
Constant Summary
-
PARTS =
# File 'activesupport/lib/active_support/duration.rb', line 130[:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
-
PARTS_IN_SECONDS =
# File 'activesupport/lib/active_support/duration.rb', line 120{ seconds: 1, minutes: SECONDS_PER_MINUTE, hours: SECONDS_PER_HOUR, days: SECONDS_PER_DAY, weeks: SECONDS_PER_WEEK, months: SECONDS_PER_MONTH, years: SECONDS_PER_YEAR }.freeze
-
SECONDS_PER_DAY =
# File 'activesupport/lib/active_support/duration.rb', line 11586400
-
SECONDS_PER_HOUR =
# File 'activesupport/lib/active_support/duration.rb', line 1143600
-
SECONDS_PER_MINUTE =
# File 'activesupport/lib/active_support/duration.rb', line 11360
-
SECONDS_PER_MONTH =
1/12 of a gregorian year
2629746
-
SECONDS_PER_WEEK =
# File 'activesupport/lib/active_support/duration.rb', line 116604800
-
SECONDS_PER_YEAR =
length of a gregorian year (365.2425 days)
31556952
-
VARIABLE_PARTS =
# File 'activesupport/lib/active_support/duration.rb', line 131[:years, :months, :weeks, :days].freeze
Class Method Summary
-
.build(value)
Creates a new
Duration
from a seconds value that is converted to the individual parts: -
.parse(iso8601duration)
Creates a new
Duration
from string formatted according to ISO 8601Duration
. - .calculate_total_seconds(parts) private
- .===(other) Internal use only
- .days(value) Internal use only
- .hours(value) Internal use only
- .minutes(value) Internal use only
- .months(value) Internal use only
- .new(value, parts, variable = nil) ⇒ Duration constructor Internal use only
- .seconds(value) Internal use only
- .weeks(value) Internal use only
- .years(value) Internal use only
Instance Attribute Summary
- #value readonly
- #variable? ⇒ Boolean readonly Internal use only
Instance Method Summary
-
#%(other)
Returns the modulo of this
Duration
by anotherDuration
or::Numeric
. -
#*(other)
Multiplies this
Duration
by a::Numeric
and returns a newDuration
. -
#+(other)
Adds another
Duration
or a::Numeric
to thisDuration
. -
#-(other)
Subtracts another
Duration
or a::Numeric
from thisDuration
. -
#/(other)
Divides this
Duration
by a::Numeric
and returns a newDuration
. -
#<=>(other)
Compares one
Duration
with another or a::Numeric
to thisDuration
. -
#==(other)
Returns
true
ifother
is also aDuration
instance with the same #value, or ifother == value
. -
#after(time = ::Time.current)
Alias for #since.
- #ago(time = ::Time.current) (also: #until, #before)
-
#before(time = ::Time.current)
Alias for #ago.
-
#eql?(other) ⇒ Boolean
Returns
true
ifother
is also aDuration
instance, which has the same parts as this one. -
#from_now(time = ::Time.current)
Alias for #since.
- #hash
-
#in_days
Returns the amount of days a duration covers as a float.
-
#in_hours
Returns the amount of hours a duration covers as a float.
-
#in_minutes
Returns the amount of minutes a duration covers as a float.
-
#in_months
Returns the amount of months a duration covers as a float.
-
#in_seconds
Alias for #to_i.
-
#in_weeks
Returns the amount of weeks a duration covers as a float.
-
#in_years
Returns the amount of years a duration covers as a float.
-
#iso8601(precision: nil)
Build ISO 8601
Duration
string for this duration. -
#kind_of?(klass)
Alias for #is_a?.
-
#parts
Returns a copy of the parts hash that defines the duration.
- #since(time = ::Time.current) (also: #from_now, #after)
-
#to_i
(also: #in_seconds)
Returns the number of seconds that this
Duration
represents. -
#to_s
Returns the amount of seconds a duration covers as a string.
-
#until(time = ::Time.current)
Alias for #ago.
- #method_missing private
- #raise_type_error(other) private
- #respond_to_missing?(method, _) ⇒ Boolean private
- #sum(sign, time = ::Time.current) private
- #+@ Internal use only
- #-@ Internal use only
- #_parts Internal use only
- #as_json(options = nil) Internal use only
- #coerce(other) Internal use only
- #encode_with(coder) Internal use only
- #init_with(coder) Internal use only
- #inspect Internal use only
- #instance_of?(klass) ⇒ Boolean Internal use only
- #is_a?(klass) ⇒ Boolean (also: #kind_of?) Internal use only
Constructor Details
.new(value, parts, variable = nil) ⇒ Duration
# File 'activesupport/lib/active_support/duration.rb', line 226
def initialize(value, parts, variable = nil) # :nodoc: @value, @parts = value, parts @parts.reject! { |k, v| v.zero? } unless value == 0 @parts.freeze @variable = variable if @variable.nil? @variable = @parts.any? { |part, _| VARIABLE_PARTS.include?(part) } end end
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing (private)
[ GitHub ]# File 'activesupport/lib/active_support/duration.rb', line 516
def method_missing(...) value.public_send(...) end
Class Method Details
.===(other)
# File 'activesupport/lib/active_support/duration.rb', line 149
def ===(other) # :nodoc: other.is_a?(Duration) rescue ::NoMethodError false end
.build(value)
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 189
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
.calculate_total_seconds(parts) (private)
[ GitHub ]# File 'activesupport/lib/active_support/duration.rb', line 217
def calculate_total_seconds(parts) parts.inject(0) do |total, (part, value)| total + value * PARTS_IN_SECONDS[part] end end
.days(value)
# File 'activesupport/lib/active_support/duration.rb', line 167
def days(value) # :nodoc: new(value * SECONDS_PER_DAY, { days: value }, true) end
.hours(value)
# File 'activesupport/lib/active_support/duration.rb', line 163
def hours(value) # :nodoc: new(value * SECONDS_PER_HOUR, { hours: value }, false) end
.minutes(value)
# File 'activesupport/lib/active_support/duration.rb', line 159
def minutes(value) # :nodoc: new(value * SECONDS_PER_MINUTE, { minutes: value }, false) end
.months(value)
# File 'activesupport/lib/active_support/duration.rb', line 175
def months(value) # :nodoc: new(value * SECONDS_PER_MONTH, { months: value }, true) end
.parse(iso8601duration)
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 Duration::ISO8601Parser::ParsingError
.
# File 'activesupport/lib/active_support/duration.rb', line 144
def parse(iso8601duration) parts = ISO8601Parser.new(iso8601duration).parse! new(calculate_total_seconds(parts), parts) end
.seconds(value)
.weeks(value)
# File 'activesupport/lib/active_support/duration.rb', line 171
def weeks(value) # :nodoc: new(value * SECONDS_PER_WEEK, { weeks: value }, true) end
.years(value)
# File 'activesupport/lib/active_support/duration.rb', line 179
def years(value) # :nodoc: new(value * SECONDS_PER_YEAR, { years: value }, true) end
Instance Attribute Details
#value (readonly)
[ GitHub ]# File 'activesupport/lib/active_support/duration.rb', line 133
attr_reader :value
#variable? ⇒ Boolean
(readonly)
# File 'activesupport/lib/active_support/duration.rb', line 477
def variable? # :nodoc: @variable end
Instance Method Details
#%(other)
#*(other)
Multiplies this Duration
by a ::Numeric
and returns a new Duration
.
# File 'activesupport/lib/active_support/duration.rb', line 287
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
#+(other)
[ GitHub ]# File 'activesupport/lib/active_support/duration.rb', line 268
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
#+@
# File 'activesupport/lib/active_support/duration.rb', line 326
def +@ # :nodoc: self end
#-(other)
# File 'activesupport/lib/active_support/duration.rb', line 282
def -(other) self + (-other) end
#-@
#/(other)
Divides this Duration
by a ::Numeric
and returns a new Duration
.
# File 'activesupport/lib/active_support/duration.rb', line 298
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
#<=>(other)
#==(other)
Returns true
if other
is also a Duration
instance with the same #value, or if other == value
.
#_parts
# File 'activesupport/lib/active_support/duration.rb', line 481
def _parts # :nodoc: @parts end
#after(time = ::Time.current)
Alias for #since.
# File 'activesupport/lib/active_support/duration.rb', line 440
alias :after :since
#ago(time = ::Time.current) Also known as: #until, #before
[ GitHub ]#as_json(options = nil)
# File 'activesupport/lib/active_support/duration.rb', line 459
def as_json( = nil) # :nodoc: to_i end
#before(time = ::Time.current)
Alias for #ago.
# File 'activesupport/lib/active_support/duration.rb', line 448
alias :before :ago
#coerce(other)
#encode_with(coder)
# File 'activesupport/lib/active_support/duration.rb', line 467
def encode_with(coder) # :nodoc: coder.map = { "value" => @value, "parts" => @parts } end
#eql?(other) ⇒ Boolean
Returns true
if other
is also a Duration
instance, which has the same parts as this one.
#from_now(time = ::Time.current)
Alias for #since.
# File 'activesupport/lib/active_support/duration.rb', line 439
alias :from_now :since
#hash
[ GitHub ]# File 'activesupport/lib/active_support/duration.rb', line 430
def hash @value.hash end
#in_days
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 399
def in_days in_seconds / SECONDS_PER_DAY.to_f end
#in_hours
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 392
def in_hours in_seconds / SECONDS_PER_HOUR.to_f end
#in_minutes
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 385
def in_minutes in_seconds / SECONDS_PER_MINUTE.to_f end
#in_months
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 413
def in_months in_seconds / SECONDS_PER_MONTH.to_f end
#in_seconds
Alias for #to_i.
# File 'activesupport/lib/active_support/duration.rb', line 380
alias :in_seconds :to_i
#in_weeks
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 406
def in_weeks in_seconds / SECONDS_PER_WEEK.to_f end
#in_years
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 420
def in_years in_seconds / SECONDS_PER_YEAR.to_f end
#init_with(coder)
# File 'activesupport/lib/active_support/duration.rb', line 463
def init_with(coder) # :nodoc: initialize(coder["value"], coder["parts"]) end
#inspect
#instance_of?(klass) ⇒ Boolean
# File 'activesupport/lib/active_support/duration.rb', line 335
def instance_of?(klass) # :nodoc: Duration == klass || value.instance_of?(klass) end
#is_a?(klass) ⇒ Boolean
Also known as: #kind_of?
# File 'activesupport/lib/active_support/duration.rb', line 330
def is_a?(klass) # :nodoc: Duration == klass || value.is_a?(klass) end
#iso8601(precision: nil)
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 473
def iso8601(precision: nil) ISO8601Serializer.new(self, precision: precision).serialize end
#kind_of?(klass)
Alias for #is_a?.
# File 'activesupport/lib/active_support/duration.rb', line 333
alias :kind_of? :is_a?
#parts
# File 'activesupport/lib/active_support/duration.rb', line 241
def parts @parts.dup end
#raise_type_error(other) (private)
# File 'activesupport/lib/active_support/duration.rb', line 520
def raise_type_error(other) raise TypeError, "no implicit conversion of #{other.class} into #{self.class}" end
#respond_to_missing?(method, _) ⇒ Boolean
(private)
# File 'activesupport/lib/active_support/duration.rb', line 512
def respond_to_missing?(method, _) value.respond_to?(method) end
#since(time = ::Time.current) Also known as: #from_now, #after
[ GitHub ]#sum(sign, time = ::Time.current) (private)
[ GitHub ]# File 'activesupport/lib/active_support/duration.rb', line 486
def sum(sign, time = ::Time.current) unless time.acts_like?(:time) || time.acts_like?(:date) raise ::ArgumentError, "expected a time or date, got #{time.inspect}" end if @parts.empty? time.since(sign * value) else @parts.each do |type, number| t = time time = if type == :seconds t.since(sign * number) elsif type == :minutes t.since(sign * number * 60) elsif type == :hours t.since(sign * number * 3600) else t.advance(type => sign * number) end end time end end
#to_i Also known as: #in_seconds
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 377
def to_i @value.to_i end
#to_s
Returns the amount of seconds a duration covers as a string. For more information check to_i method.
1.day.to_s # => "86400"
# File 'activesupport/lib/active_support/duration.rb', line 353
def to_s @value.to_s end
#until(time = ::Time.current)
Alias for #ago.
# File 'activesupport/lib/active_support/duration.rb', line 447
alias :until :ago