Class: ActiveSupport::Duration
- Defined in:
- lib/active_support/duration.rb,
lib/active_support/duration/iso8601_parser.rb,
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)
Defined Under Namespace
Classes: ISO8601Parser, ISO8601Serializer, Scalar
Constant Summary collapse
- SECONDS_PER_MINUTE =
60
- SECONDS_PER_HOUR =
3600
- SECONDS_PER_DAY =
86400
- SECONDS_PER_WEEK =
604800
- SECONDS_PER_MONTH =
1/12 of a gregorian year
2629746
- SECONDS_PER_YEAR =
length of a gregorian year (365.2425 days)
31556952
- PARTS_IN_SECONDS =
{ 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
- PARTS =
[:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
Instance Attribute Summary collapse
-
#parts ⇒ Object
Returns the value of attribute parts.
-
#value ⇒ Object
Returns the value of attribute value.
Class Method Summary collapse
-
.===(other) ⇒ Object
:nodoc:.
-
.build(value) ⇒ Object
Creates a new Duration from a seconds value that is converted to the individual parts:.
-
.days(value) ⇒ Object
:nodoc:.
-
.hours(value) ⇒ Object
:nodoc:.
-
.minutes(value) ⇒ Object
:nodoc:.
-
.months(value) ⇒ Object
:nodoc:.
-
.parse(iso8601duration) ⇒ Object
Creates a new Duration from string formatted according to ISO 8601 Duration.
-
.seconds(value) ⇒ Object
:nodoc:.
-
.weeks(value) ⇒ Object
:nodoc:.
-
.years(value) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#%(other) ⇒ Object
Returns the modulo of this Duration by another Duration or Numeric.
-
#*(other) ⇒ Object
Multiplies this Duration by a Numeric and returns a new Duration.
-
#+(other) ⇒ Object
Adds another Duration or a Numeric to this Duration.
-
#+@ ⇒ Object
:nodoc:.
-
#-(other) ⇒ Object
Subtracts another Duration or a Numeric from this Duration.
-
#-@ ⇒ Object
:nodoc:.
-
#/(other) ⇒ Object
Divides this Duration by a Numeric and returns a new Duration.
-
#<=>(other) ⇒ Object
Compares one Duration with another or a Numeric to this Duration.
-
#==(other) ⇒ Object
Returns
true
ifother
is also a Duration instance with the samevalue
, or ifother == value
. -
#ago(time = ::Time.current) ⇒ Object
(also: #until, #before)
Calculates a new Time or Date that is as far in the past as this Duration represents.
-
#as_json(options = nil) ⇒ Object
:nodoc:.
-
#coerce(other) ⇒ Object
:nodoc:.
-
#encode_with(coder) ⇒ Object
:nodoc:.
-
#eql?(other) ⇒ Boolean
Returns
true
ifother
is also a Duration instance, which has the same parts as this one. - #hash ⇒ Object
-
#in_days ⇒ Object
Returns the amount of days a duration covers as a float.
-
#in_hours ⇒ Object
Returns the amount of hours a duration covers as a float.
-
#in_minutes ⇒ Object
Returns the amount of minutes a duration covers as a float.
-
#in_months ⇒ Object
Returns the amount of months a duration covers as a float.
-
#in_weeks ⇒ Object
Returns the amount of weeks a duration covers as a float.
-
#in_years ⇒ Object
Returns the amount of years a duration covers as a float.
-
#init_with(coder) ⇒ Object
:nodoc:.
-
#initialize(value, parts) ⇒ Duration
constructor
:nodoc:.
-
#inspect ⇒ Object
:nodoc:.
-
#instance_of?(klass) ⇒ Boolean
:nodoc:.
-
#is_a?(klass) ⇒ Boolean
(also: #kind_of?)
:nodoc:.
-
#iso8601(precision: nil) ⇒ Object
Build ISO 8601 Duration string for this duration.
-
#since(time = ::Time.current) ⇒ Object
(also: #from_now, #after)
Calculates a new Time or Date that is as far in the future as this Duration represents.
-
#to_i ⇒ Object
(also: #in_seconds)
Returns the number of seconds that this Duration represents.
-
#to_s ⇒ Object
Returns the amount of seconds a duration covers as a string.
Constructor Details
#initialize(value, parts) ⇒ Duration
:nodoc:
213 214 215 216 |
# File 'lib/active_support/duration.rb', line 213 def initialize(value, parts) #:nodoc: @value, @parts = value, parts @parts.reject! { |k, v| v.zero? } unless value == 0 end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object (private)
477 478 479 |
# File 'lib/active_support/duration.rb', line 477 def method_missing(method, *args, &block) value.public_send(method, *args, &block) end |
Instance Attribute Details
#parts ⇒ Object
Returns the value of attribute parts.
127 128 129 |
# File 'lib/active_support/duration.rb', line 127 def parts @parts end |
#value ⇒ Object
Returns the value of attribute value.
127 128 129 |
# File 'lib/active_support/duration.rb', line 127 def value @value end |
Class Method Details
.===(other) ⇒ Object
:nodoc:
143 144 145 146 147 |
# File 'lib/active_support/duration.rb', line 143 def ===(other) #:nodoc: other.is_a?(Duration) rescue ::NoMethodError false end |
.build(value) ⇒ Object
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}
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/active_support/duration.rb', line 183 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 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 end end unless value == 0 parts[:seconds] = remainder * remainder_sign new(value, parts) end |
.days(value) ⇒ Object
:nodoc:
161 162 163 |
# File 'lib/active_support/duration.rb', line 161 def days(value) #:nodoc: new(value * SECONDS_PER_DAY, days: value) end |
.hours(value) ⇒ Object
:nodoc:
157 158 159 |
# File 'lib/active_support/duration.rb', line 157 def hours(value) #:nodoc: new(value * SECONDS_PER_HOUR, hours: value) end |
.minutes(value) ⇒ Object
:nodoc:
153 154 155 |
# File 'lib/active_support/duration.rb', line 153 def minutes(value) #:nodoc: new(value * SECONDS_PER_MINUTE, minutes: value) end |
.months(value) ⇒ Object
:nodoc:
169 170 171 |
# File 'lib/active_support/duration.rb', line 169 def months(value) #:nodoc: new(value * SECONDS_PER_MONTH, months: value) end |
.parse(iso8601duration) ⇒ Object
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
.
138 139 140 141 |
# File 'lib/active_support/duration.rb', line 138 def parse(iso8601duration) parts = ISO8601Parser.new(iso8601duration).parse! new(calculate_total_seconds(parts), parts) end |
.seconds(value) ⇒ Object
:nodoc:
149 150 151 |
# File 'lib/active_support/duration.rb', line 149 def seconds(value) #:nodoc: new(value, seconds: value) end |
.weeks(value) ⇒ Object
:nodoc:
165 166 167 |
# File 'lib/active_support/duration.rb', line 165 def weeks(value) #:nodoc: new(value * SECONDS_PER_WEEK, weeks: value) end |
.years(value) ⇒ Object
:nodoc:
173 174 175 |
# File 'lib/active_support/duration.rb', line 173 def years(value) #:nodoc: new(value * SECONDS_PER_YEAR, years: value) end |
Instance Method Details
#%(other) ⇒ Object
Returns the modulo of this Duration by another Duration or Numeric. Numeric values are treated as seconds.
285 286 287 288 289 290 291 292 293 |
# File 'lib/active_support/duration.rb', line 285 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 |
#*(other) ⇒ Object
Multiplies this Duration by a Numeric and returns a new Duration.
260 261 262 263 264 265 266 267 268 |
# File 'lib/active_support/duration.rb', line 260 def *(other) if Scalar === other || Duration === other Duration.new(value * other.value, parts.transform_values { |number| number * other.value }) elsif Numeric === other Duration.new(value * other, parts.transform_values { |number| number * other }) else raise_type_error(other) end end |
#+(other) ⇒ Object
Adds another Duration or a Numeric to this Duration. Numeric values are treated as seconds.
241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/active_support/duration.rb', line 241 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) else seconds = @parts.fetch(:seconds, 0) + other Duration.new(value + other, @parts.merge(seconds: seconds)) end end |
#+@ ⇒ Object
:nodoc:
299 300 301 |
# File 'lib/active_support/duration.rb', line 299 def +@ #:nodoc: self end |
#-(other) ⇒ Object
Subtracts another Duration or a Numeric from this Duration. Numeric values are treated as seconds.
255 256 257 |
# File 'lib/active_support/duration.rb', line 255 def -(other) self + (-other) end |
#-@ ⇒ Object
:nodoc:
295 296 297 |
# File 'lib/active_support/duration.rb', line 295 def -@ #:nodoc: Duration.new(-value, parts.transform_values(&:-@)) end |
#/(other) ⇒ Object
Divides this Duration by a Numeric and returns a new Duration.
271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/active_support/duration.rb', line 271 def /(other) if Scalar === other Duration.new(value / other.value, parts.transform_values { |number| number / other.value }) elsif Duration === other value / other.value elsif Numeric === other Duration.new(value / other, parts.transform_values { |number| number / other }) else raise_type_error(other) end end |
#<=>(other) ⇒ Object
Compares one Duration with another or a Numeric to this Duration. Numeric values are treated as seconds.
231 232 233 234 235 236 237 |
# File 'lib/active_support/duration.rb', line 231 def <=>(other) if Duration === other value <=> other.value elsif Numeric === other value <=> other end end |
#==(other) ⇒ Object
Returns true
if other
is also a Duration instance with the same value
, or if other == value
.
314 315 316 317 318 319 320 |
# File 'lib/active_support/duration.rb', line 314 def ==(other) if Duration === other other.value == value else other == value end end |
#ago(time = ::Time.current) ⇒ Object Also known as: until, before
Calculates a new Time or Date that is as far in the past as this Duration represents.
417 418 419 |
# File 'lib/active_support/duration.rb', line 417 def ago(time = ::Time.current) sum(-1, time) end |
#as_json(options = nil) ⇒ Object
:nodoc:
432 433 434 |
# File 'lib/active_support/duration.rb', line 432 def as_json( = nil) #:nodoc: to_i end |
#coerce(other) ⇒ Object
:nodoc:
218 219 220 221 222 223 224 225 226 227 |
# File 'lib/active_support/duration.rb', line 218 def coerce(other) #:nodoc: case other when Scalar [other, self] when Duration [Scalar.new(other.value), self] else [Scalar.new(other), self] end end |
#encode_with(coder) ⇒ Object
:nodoc:
440 441 442 |
# File 'lib/active_support/duration.rb', line 440 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.
399 400 401 |
# File 'lib/active_support/duration.rb', line 399 def eql?(other) Duration === other && other.value.eql?(value) end |
#hash ⇒ Object
403 404 405 |
# File 'lib/active_support/duration.rb', line 403 def hash @value.hash end |
#in_days ⇒ Object
Returns the amount of days a duration covers as a float
12.hours.in_days # => 0.5
372 373 374 |
# File 'lib/active_support/duration.rb', line 372 def in_days in_seconds / SECONDS_PER_DAY.to_f end |
#in_hours ⇒ Object
Returns the amount of hours a duration covers as a float
1.day.in_hours # => 24.0
365 366 367 |
# File 'lib/active_support/duration.rb', line 365 def in_hours in_seconds / SECONDS_PER_HOUR.to_f end |
#in_minutes ⇒ Object
Returns the amount of minutes a duration covers as a float
1.day.in_minutes # => 1440.0
358 359 360 |
# File 'lib/active_support/duration.rb', line 358 def in_minutes in_seconds / SECONDS_PER_MINUTE.to_f end |
#in_months ⇒ Object
Returns the amount of months a duration covers as a float
9.weeks.in_months # => 2.07
386 387 388 |
# File 'lib/active_support/duration.rb', line 386 def in_months in_seconds / SECONDS_PER_MONTH.to_f end |
#in_weeks ⇒ Object
Returns the amount of weeks a duration covers as a float
2.months.in_weeks # => 8.696
379 380 381 |
# File 'lib/active_support/duration.rb', line 379 def in_weeks in_seconds / SECONDS_PER_WEEK.to_f end |
#in_years ⇒ Object
Returns the amount of years a duration covers as a float
30.days.in_years # => 0.082
393 394 395 |
# File 'lib/active_support/duration.rb', line 393 def in_years in_seconds / SECONDS_PER_YEAR.to_f end |
#init_with(coder) ⇒ Object
:nodoc:
436 437 438 |
# File 'lib/active_support/duration.rb', line 436 def init_with(coder) #:nodoc: initialize(coder["value"], coder["parts"]) end |
#inspect ⇒ Object
:nodoc:
423 424 425 426 427 428 429 430 |
# File 'lib/active_support/duration.rb', line 423 def inspect #:nodoc: return "#{value} seconds" if parts.empty? parts. sort_by { |unit, _ | PARTS.index(unit) }. map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }. to_sentence(locale: ::I18n.default_locale) end |
#instance_of?(klass) ⇒ Boolean
:nodoc:
308 309 310 |
# File 'lib/active_support/duration.rb', line 308 def instance_of?(klass) # :nodoc: Duration == klass || value.instance_of?(klass) end |
#is_a?(klass) ⇒ Boolean Also known as: kind_of?
:nodoc:
303 304 305 |
# File 'lib/active_support/duration.rb', line 303 def is_a?(klass) #:nodoc: Duration == klass || value.is_a?(klass) end |
#iso8601(precision: nil) ⇒ Object
Build ISO 8601 Duration string for this duration. The precision
parameter can be used to limit seconds’ precision of duration.
446 447 448 |
# File 'lib/active_support/duration.rb', line 446 def iso8601(precision: nil) ISO8601Serializer.new(self, precision: precision).serialize end |
#since(time = ::Time.current) ⇒ Object Also known as: from_now, after
Calculates a new Time or Date that is as far in the future as this Duration represents.
409 410 411 |
# File 'lib/active_support/duration.rb', line 409 def since(time = ::Time.current) sum(1, time) end |
#to_i ⇒ Object 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.
350 351 352 |
# File 'lib/active_support/duration.rb', line 350 def to_i @value.to_i end |
#to_s ⇒ Object
Returns the amount of seconds a duration covers as a string. For more information check to_i method.
1.day.to_s # => "86400"
326 327 328 |
# File 'lib/active_support/duration.rb', line 326 def to_s @value.to_s end |