123456789_123456789_123456789_123456789_123456789_

Class: ActiveSupport::Duration::ISO8601Serializer

Do not use. This class is for internal use only.
Relationships & Source Files
Inherits: Object
Defined in: activesupport/lib/active_support/duration/iso8601_serializer.rb

Overview

Serializes duration to string according to ISO 8601 ::ActiveSupport::Duration format.

Constant Summary

Class Method Summary

Instance Method Summary

Constructor Details

.new(duration, precision: nil) ⇒ ISO8601Serializer

[ GitHub ]

  
# File 'activesupport/lib/active_support/duration/iso8601_serializer.rb', line 12

def initialize(duration, precision: nil)
  @duration = duration
  @precision = precision
end

Instance Method Details

#format_number(number) (private)

Float#to_s uses scientific notation for very small and very large values (e.g. "5.0e-05") and Rational#to_s writes a fraction ("3/2"), neither of which is valid in ISO 8601.

[ GitHub ]

  
# File 'activesupport/lib/active_support/duration/iso8601_serializer.rb', line 69

def format_number(number)
  case number
  when Integer
    number
  when Float
    str = number.to_s
    if str.include?("e")
      BigDecimal(str).to_s("F")
    else
      str
    end
  when Rational
    format_number(number.to_f)
  else
    number.to_s
  end
end

#format_seconds(seconds) (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/duration/iso8601_serializer.rb', line 58

def format_seconds(seconds)
  if @precision
    sprintf("%0.0#{@precision}f", seconds)
  else
    format_number(seconds)
  end
end

#normalize (private)

Return pair of duration's parts and whole duration sign. Parts are summarized (as they can become repetitive due to addition, etc). Zero parts are removed as not significant.

[ GitHub ]

  
# File 'activesupport/lib/active_support/duration/iso8601_serializer.rb', line 41

def normalize
  parts = @duration.parts.each_with_object(Hash.new(0)) do |(k, v), p|
    p[k] += v  unless v.zero?
  end

  # Convert weeks to days and remove weeks if mixed with date parts
  if week_mixed_with_date?(parts)
    parts[:days] += parts.delete(:weeks) * SECONDS_PER_WEEK / SECONDS_PER_DAY
  end

  parts
end

#serialize

Builds and returns output string.

[ GitHub ]

  
# File 'activesupport/lib/active_support/duration/iso8601_serializer.rb', line 18

def serialize
  parts = normalize
  return "PT0S" if parts.empty?

  output = +"P"
  output << "#{format_number(parts[:years])}Y"   if parts.key?(:years)
  output << "#{format_number(parts[:months])}M"  if parts.key?(:months)
  output << "#{format_number(parts[:days])}D"    if parts.key?(:days)
  output << "#{format_number(parts[:weeks])}W"   if parts.key?(:weeks)
  time = +""
  time << "#{format_number(parts[:hours])}H"     if parts.key?(:hours)
  time << "#{format_number(parts[:minutes])}M"   if parts.key?(:minutes)
  if parts.key?(:seconds)
    time << "#{format_seconds(parts[:seconds])}S"
  end
  output << "T#{time}" unless time.empty?
  output
end

#week_mixed_with_date?(parts) ⇒ Boolean (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/duration/iso8601_serializer.rb', line 54

def week_mixed_with_date?(parts)
  parts.key?(:weeks) && parts.keys.intersect?(DATE_COMPONENTS)
end