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 =
# File 'activesupport/lib/active_support/duration.rb', line 117
1/12 of a gregorian year
2629746 -
SECONDS_PER_WEEK =
# File 'activesupport/lib/active_support/duration.rb', line 116604800 -
SECONDS_PER_YEAR =
# File 'activesupport/lib/active_support/duration.rb', line 118
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
Durationfrom a seconds value that is converted to the individual parts: -
.parse(iso8601duration)
Creates a new
Durationfrom 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
Durationby anotherDurationor::Numeric. -
#*(other)
Multiplies this
Durationby a::Numericand returns a newDuration. -
#+(other)
Adds another
Durationor a::Numericto thisDuration. -
#-(other)
Subtracts another
Durationor a::Numericfrom thisDuration. -
#/(other)
Divides this
Durationby a::Numericand returns a newDuration. -
#<=>(other)
Compares one
Durationwith another or a::Numericto thisDuration. -
#==(other)
Returns
trueifotheris also aDurationinstance 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
trueifotheris also aDurationinstance, 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
Durationstring 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
Durationrepresents. -
#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