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.
-
#-(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
-
#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
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:
210 211 212 213 214 |
# File 'lib/active_support/duration.rb', line 210 def initialize(value, parts) #:nodoc: @value, @parts = value, parts.to_h @parts.default = 0 @parts.reject! { |k, v| v.zero? } end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object (private)
424 425 426 |
# File 'lib/active_support/duration.rb', line 424 def method_missing(method, *args, &block) value.public_send(method, *args, &block) end |
Instance Attribute Details
#parts ⇒ Object
Returns the value of attribute parts.
128 129 130 |
# File 'lib/active_support/duration.rb', line 128 def parts @parts end |
#value ⇒ Object
Returns the value of attribute value.
128 129 130 |
# File 'lib/active_support/duration.rb', line 128 def value @value end |
Class Method Details
.===(other) ⇒ Object
:nodoc:
144 145 146 147 148 |
# File 'lib/active_support/duration.rb', line 144 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}
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/active_support/duration.rb', line 184 def build(value) parts = {} remainder = value.to_f PARTS.each do |part| unless part == :seconds part_in_seconds = PARTS_IN_SECONDS[part] parts[part] = remainder.div(part_in_seconds) remainder = (remainder % part_in_seconds).round(9) end end parts[:seconds] = remainder new(value, parts) end |
.days(value) ⇒ Object
:nodoc:
162 163 164 |
# File 'lib/active_support/duration.rb', line 162 def days(value) #:nodoc: new(value * SECONDS_PER_DAY, [[:days, value]]) end |
.hours(value) ⇒ Object
:nodoc:
158 159 160 |
# File 'lib/active_support/duration.rb', line 158 def hours(value) #:nodoc: new(value * SECONDS_PER_HOUR, [[:hours, value]]) end |
.minutes(value) ⇒ Object
:nodoc:
154 155 156 |
# File 'lib/active_support/duration.rb', line 154 def minutes(value) #:nodoc: new(value * SECONDS_PER_MINUTE, [[:minutes, value]]) end |
.months(value) ⇒ Object
:nodoc:
170 171 172 |
# File 'lib/active_support/duration.rb', line 170 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
.
139 140 141 142 |
# File 'lib/active_support/duration.rb', line 139 def parse(iso8601duration) parts = ISO8601Parser.new(iso8601duration).parse! new(calculate_total_seconds(parts), parts) end |
.seconds(value) ⇒ Object
:nodoc:
150 151 152 |
# File 'lib/active_support/duration.rb', line 150 def seconds(value) #:nodoc: new(value, [[:seconds, value]]) end |
.weeks(value) ⇒ Object
:nodoc:
166 167 168 |
# File 'lib/active_support/duration.rb', line 166 def weeks(value) #:nodoc: new(value * SECONDS_PER_WEEK, [[:weeks, value]]) end |
.years(value) ⇒ Object
:nodoc:
174 175 176 |
# File 'lib/active_support/duration.rb', line 174 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.
281 282 283 284 285 286 287 288 289 |
# File 'lib/active_support/duration.rb', line 281 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.
256 257 258 259 260 261 262 263 264 |
# File 'lib/active_support/duration.rb', line 256 def *(other) if Scalar === other || Duration === other Duration.new(value * other.value, parts.map { |type, number| [type, number * other.value] }) elsif Numeric === other Duration.new(value * other, parts.map { |type, number| [type, 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.
236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/active_support/duration.rb', line 236 def +(other) if Duration === other parts = @parts.dup other.parts.each do |(key, value)| parts[key] += value end Duration.new(value + other.value, parts) else seconds = @parts[:seconds] + other Duration.new(value + other, @parts.merge(seconds: seconds)) end end |
#-(other) ⇒ Object
Subtracts another Duration or a Numeric from this Duration. Numeric values are treated as seconds.
251 252 253 |
# File 'lib/active_support/duration.rb', line 251 def -(other) self + (-other) end |
#-@ ⇒ Object
:nodoc:
291 292 293 |
# File 'lib/active_support/duration.rb', line 291 def -@ #:nodoc: Duration.new(-value, parts.map { |type, number| [type, -number] }) end |
#/(other) ⇒ Object
Divides this Duration by a Numeric and returns a new Duration.
267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/active_support/duration.rb', line 267 def /(other) if Scalar === other Duration.new(value / other.value, parts.map { |type, number| [type, number / other.value] }) elsif Duration === other value / other.value elsif Numeric === other Duration.new(value / other, parts.map { |type, number| [type, 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.
226 227 228 229 230 231 232 |
# File 'lib/active_support/duration.rb', line 226 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
.
306 307 308 309 310 311 312 |
# File 'lib/active_support/duration.rb', line 306 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.
366 367 368 |
# File 'lib/active_support/duration.rb', line 366 def ago(time = ::Time.current) sum(-1, time) end |
#as_json(options = nil) ⇒ Object
:nodoc:
382 383 384 |
# File 'lib/active_support/duration.rb', line 382 def as_json( = nil) #:nodoc: to_i end |
#coerce(other) ⇒ Object
:nodoc:
216 217 218 219 220 221 222 |
# File 'lib/active_support/duration.rb', line 216 def coerce(other) #:nodoc: if Scalar === other [other, self] else [Scalar.new(other), self] end end |
#encode_with(coder) ⇒ Object
:nodoc:
390 391 392 |
# File 'lib/active_support/duration.rb', line 390 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.
348 349 350 |
# File 'lib/active_support/duration.rb', line 348 def eql?(other) Duration === other && other.value.eql?(value) end |
#hash ⇒ Object
352 353 354 |
# File 'lib/active_support/duration.rb', line 352 def hash @value.hash end |
#init_with(coder) ⇒ Object
:nodoc:
386 387 388 |
# File 'lib/active_support/duration.rb', line 386 def init_with(coder) #:nodoc: initialize(coder["value"], coder["parts"]) end |
#inspect ⇒ Object
:nodoc:
372 373 374 375 376 377 378 379 380 |
# File 'lib/active_support/duration.rb', line 372 def inspect #:nodoc: return "0 seconds" if parts.empty? parts. reduce(::Hash.new(0)) { |h, (l, r)| h[l] += r; h }. 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:
300 301 302 |
# File 'lib/active_support/duration.rb', line 300 def instance_of?(klass) # :nodoc: Duration == klass || value.instance_of?(klass) end |
#is_a?(klass) ⇒ Boolean Also known as: kind_of?
:nodoc:
295 296 297 |
# File 'lib/active_support/duration.rb', line 295 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.
396 397 398 |
# File 'lib/active_support/duration.rb', line 396 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.
358 359 360 |
# File 'lib/active_support/duration.rb', line 358 def since(time = ::Time.current) sum(1, time) end |
#to_i ⇒ Object
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.
342 343 344 |
# File 'lib/active_support/duration.rb', line 342 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"
318 319 320 |
# File 'lib/active_support/duration.rb', line 318 def to_s @value.to_s end |