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 141[:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
-
PARTS_IN_SECONDS =
# File 'activesupport/lib/active_support/duration.rb', line 131{ 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 11886400 -
SECONDS_PER_DAY_F =
private
# File 'activesupport/lib/active_support/duration.rb', line 125SECONDS_PER_DAY.to_f
-
SECONDS_PER_HOUR =
# File 'activesupport/lib/active_support/duration.rb', line 1173600 -
SECONDS_PER_HOUR_F =
private
# File 'activesupport/lib/active_support/duration.rb', line 124SECONDS_PER_HOUR.to_f
-
SECONDS_PER_MINUTE =
# File 'activesupport/lib/active_support/duration.rb', line 11660 -
SECONDS_PER_MINUTE_F =
private
# File 'activesupport/lib/active_support/duration.rb', line 123SECONDS_PER_MINUTE.to_f
-
SECONDS_PER_MONTH =
# File 'activesupport/lib/active_support/duration.rb', line 120
1/12 of a gregorian year
2629746 -
SECONDS_PER_MONTH_F =
private
# File 'activesupport/lib/active_support/duration.rb', line 127SECONDS_PER_MONTH.to_f
-
SECONDS_PER_WEEK =
# File 'activesupport/lib/active_support/duration.rb', line 119604800 -
SECONDS_PER_WEEK_F =
private
# File 'activesupport/lib/active_support/duration.rb', line 126SECONDS_PER_WEEK.to_f
-
SECONDS_PER_YEAR =
# File 'activesupport/lib/active_support/duration.rb', line 121
length of a gregorian year (365.2425 days)
31556952 -
SECONDS_PER_YEAR_F =
private
# File 'activesupport/lib/active_support/duration.rb', line 128SECONDS_PER_YEAR.to_f
-
VARIABLE_PARTS =
# File 'activesupport/lib/active_support/duration.rb', line 142[: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 239
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 549
def method_missing(...) value.public_send(...) end
Class Method Details
.===(other)
# File 'activesupport/lib/active_support/duration.rb', line 160
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:
<code>build</code>(31556952).parts # => {:years=>1}
<code>build</code>(2716146).parts # => {:months=>1, :days=>1}
# File 'activesupport/lib/active_support/duration.rb', line 202
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 230
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 178
def days(value) # :nodoc: new(value * SECONDS_PER_DAY, { days: value }, true) end
.hours(value)
# File 'activesupport/lib/active_support/duration.rb', line 174
def hours(value) # :nodoc: new(value * SECONDS_PER_HOUR, { hours: value }, false) end
.minutes(value)
# File 'activesupport/lib/active_support/duration.rb', line 170
def minutes(value) # :nodoc: new(value * SECONDS_PER_MINUTE, { minutes: value }, false) end
.months(value)
# File 'activesupport/lib/active_support/duration.rb', line 186
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.
SeeISO 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 155
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 182
def weeks(value) # :nodoc: new(value * SECONDS_PER_WEEK, { weeks: value }, true) end
.years(value)
# File 'activesupport/lib/active_support/duration.rb', line 190
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 144
attr_reader :value
#variable? ⇒ Boolean (readonly)
# File 'activesupport/lib/active_support/duration.rb', line 510
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 302
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 283
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 341
def +@ # :nodoc: self end
#-(other)
# File 'activesupport/lib/active_support/duration.rb', line 297
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 313
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 514
def _parts # :nodoc: @parts end
#after(time = ::Time.current)
Alias for #since.
# File 'activesupport/lib/active_support/duration.rb', line 473
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 492
def as_json( = nil) # :nodoc: to_i end
#before(time = ::Time.current)
Alias for #ago.
# File 'activesupport/lib/active_support/duration.rb', line 481
alias :before :ago
#coerce(other)
#encode_with(coder)
# File 'activesupport/lib/active_support/duration.rb', line 500
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 472
alias :from_now :since
#hash
[ GitHub ]# File 'activesupport/lib/active_support/duration.rb', line 463
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 426
def in_days value / SECONDS_PER_DAY_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 417
def in_hours value / SECONDS_PER_HOUR_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 408
def in_minutes value / SECONDS_PER_MINUTE_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 444
def in_months value / SECONDS_PER_MONTH_F end
#in_seconds
Alias for #to_i.
# File 'activesupport/lib/active_support/duration.rb', line 401
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 435
def in_weeks value / SECONDS_PER_WEEK_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 453
def in_years value / SECONDS_PER_YEAR_F end
#init_with(coder)
# File 'activesupport/lib/active_support/duration.rb', line 496
def init_with(coder) # :nodoc: initialize(coder["value"], coder["parts"]) end
#inspect
#instance_of?(klass) ⇒ Boolean
# File 'activesupport/lib/active_support/duration.rb', line 350
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 345
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 506
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 348
alias :kind_of? :is_a?
#parts
# File 'activesupport/lib/active_support/duration.rb', line 256
def parts @parts.dup end
#raise_type_error(other) (private)
# File 'activesupport/lib/active_support/duration.rb', line 553
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 545
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 519
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 398
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 370
def to_s @value.to_s end
#until(time = ::Time.current)
Alias for #ago.
# File 'activesupport/lib/active_support/duration.rb', line 480
alias :until :ago