class RDF::Literal::Duration

A duration literal.

‘duration` is a datatype that represents durations of time. The concept of duration being captured is drawn from those of [ISO 8601](www.w3.org/TR/xmlschema11-2/#ISO8601), specifically durations without fixed endpoints.

@see www.w3.org/TR/xmlschema11-2/#duration

Constants

DATATYPE
GRAMMAR

Public Class Methods

new(value, datatype: nil, lexical: nil, **options) click to toggle source

Creates a new Duration instance.

  • Given a ‘String`, parse as `xsd:duration` into months and seconds

  • Given a ‘Hash` containing any of `:yr`, `:mo`, :da`, `:hr`, `:mi` and `:si`, it is transformed into months and seconds

  • Given a Rational, the result is interpreted as days, hours, minutes, and seconds.

  • Given an Integer, the result is interpreted as years and months.

  • Object representation is the ‘Array(months, seconds)`

@param [Literal::Duration, Hash, Array, Literal::Numeric, to_s] value

If provided an Array, it is the same as the object form of this literal, an array of two integers, the first of which may be negative.

@param [String] lexical (nil)

Supplied lexical representation of this literal,
otherwise it comes from transforming `value` to a string form..

@param [URI] datatype (nil) @param [Hash{Symbol => Object}] options other options passed to ‘RDF::Literal#initialize`. @option options [Boolean] :validate (false) @option options [Boolean] :canonicalize (false)

Calls superclass method
# File lib/rdf/xsd/duration.rb, line 50
def initialize(value, datatype: nil, lexical: nil, **options)
  super
  @object   = case value
  when Hash
    months = value[:yr].to_i * 12 + value[:mo].to_i
    seconds = value[:da].to_i * 3600 * 24 +
              value[:hr].to_i * 3600 +
              value[:mi].to_i * 60 +
              value[:se].to_f

    if value[:si]
      if months != 0
        months = -months
      else
        seconds = -seconds
      end
    end
    [months, seconds]
  when Rational
    [0, value * 24 * 3600]
  when Integer, ::Integer
    [value.to_i, 0]
  when Literal::Duration then value.object
  when Array then    value
  else               parse(value.to_s)
  end
end

Public Instance Methods

==(other) click to toggle source

Returns ‘true` if `self` and `other` are durations of the same length.

From the XQuery function [op:duration-equal](www.w3.org/TR/xpath-functions/#func-duration-equal).

@see www.w3.org/TR/xpath-functions/#func-duration-equal

Calls superclass method
# File lib/rdf/xsd/duration.rb, line 174
def ==(other)
  # If lexically invalid, use regular literal testing
  return super unless self.valid?

  other.is_a?(Literal::Duration) && other.valid? ? @object == other.object : super
end
canonicalize!() click to toggle source

Converts this literal into its canonical lexical representation.

@return [Literal] ‘self` @see www.w3.org/TR/xmlschema11-2/#dateTime

# File lib/rdf/xsd/duration.rb, line 83
def canonicalize!
  @string = @humanize = @hash = nil
  self.to_s  # side-effect
  self
end
days() click to toggle source

Days

From the XQuery function [fn:days-from-duration](www.w3.org/TR/xpath-functions/#func-days-from-duration).

@return [Integer] @see www.w3.org/TR/xpath-functions/#func-days-from-duration

# File lib/rdf/xsd/duration.rb, line 203
def days; Integer.new(to_h[:da] * (to_h[:si] ? -1 : 1)); end
hours() click to toggle source

Hours

From the XQuery function [fn:hours-from-duration](www.w3.org/TR/xpath-functions/#func-hours-from-duration).

@return [Integer] @see www.w3.org/TR/xpath-functions/#func-hours-from-duration

# File lib/rdf/xsd/duration.rb, line 211
def hours; Integer.new(to_h[:hr] * (to_h[:si] ? -1 : 1)); end
humanize(lang = :en) click to toggle source

Returns a human-readable value for the interval

# File lib/rdf/xsd/duration.rb, line 147
def humanize(lang = :en)
  @humanize ||= {}
  @humanize[lang] ||= begin
    # Just english, for now
    return "Invalid duration #{value.to_s.inspect}" unless valid?

    md = value.match(GRAMMAR)
    ar = []
    ar << plural(md[:yr], "year") if md[:yr]
    ar << plural(md[:mo], "month") if md[:mo]
    ar << plural(md[:da], "day") if md[:da]
    ar << plural(md[:hr], "hour") if md[:hr]
    ar << plural(md[:mi], "minute") if md[:mi]
    ar << plural(md[:se], "second") if md[:se]
    last = ar.pop
    first = ar.join(" ")
    res = first.empty? ? last : "#{first} and #{last}"
    md[:si] == '-' ? "#{res} ago" : res
  end
end
minutes() click to toggle source

Minutes

From the XQuery function [fn:minutes-from-duration](www.w3.org/TR/xpath-functions/#func-minutes-from-duration).

@return [Integer] @see www.w3.org/TR/xpath-functions/#func-minutes-from-duration

# File lib/rdf/xsd/duration.rb, line 219
def minutes; Integer.new(to_h[:mi] * (to_h[:si] ? -1 : 1)); end
months() click to toggle source

Months

From the XQuery function [fn:months-from-duration](www.w3.org/TR/xpath-functions/#func-months-from-duration).

@return [Integer] @see www.w3.org/TR/xpath-functions/#func-months-from-duration

# File lib/rdf/xsd/duration.rb, line 195
def months; Integer.new(to_h[:mo] * (to_h[:si] ? -1 : 1)); end
plural(v, str) click to toggle source
# File lib/rdf/xsd/duration.rb, line 141
def plural(v, str)
  "#{v} #{str}#{v.to_i == 1 ? '' : 's'}" if v
end
seconds() click to toggle source

Seconds

From the XQuery function [fn:seconds-from-duration](www.w3.org/TR/xpath-functions/#func-seconds-from-duration).

@return [Decimal] @see www.w3.org/TR/xpath-functions/#func-seconds-from-duration

# File lib/rdf/xsd/duration.rb, line 227
def seconds; Decimal.new(to_h[:se] * (to_h[:si] ? -1 : 1)); end
to_h() click to toggle source

Returns a hash representation.

@return [Hash]

# File lib/rdf/xsd/duration.rb, line 104
def to_h
  @hash ||= {
    si: ('-' if (@object.first == 0 ? @object.last : @object.first) < 0),
    yr: (@object.first.abs / 12),
    mo: (@object.first.abs % 12),
    da: (@object.last.abs.to_i / (3600 * 24)),
    hr: ((@object.last.abs.to_i / 3600) % 24),
    mi: ((@object.last.abs.to_i / 60) % 60),
    se: sec_str.to_f
  }
end
to_s() click to toggle source

Returns the value as a string.

@return [String]

# File lib/rdf/xsd/duration.rb, line 120
def to_s
  @string ||= begin
    hash = to_h
    str = (@object.first == 0 ? @object.last : @object.first) < 0 ? '-P' : 'P'
    hash = to_h
    str << "%dY" % hash[:yr] if hash[:yr] > 0
    str << "%dM" % hash[:mo] if hash[:mo] > 0
    str << "%dD" % hash[:da] if hash[:da] > 0
    str << "T" if (hash[:hr] + hash[:mi] + hash[:se]) > 0
    str << "%dH" % hash[:hr] if hash[:hr] > 0
    str << "%dM" % hash[:mi] if hash[:mi] > 0
    str << sec_str + 'S' if hash[:se] > 0
    # Ensure some legal representation
    if str.end_with?('P')
      is_a?(Literal::YearMonthDuration) ? 'P0M' : 'PT0S'
    else
      str
    end
  end
end
valid?() click to toggle source

Returns ‘true` if the value adheres to the defined grammar of the datatype.

Special case for date and dateTime, for which ‘0000’ is not a valid year

@return [Boolean]

# File lib/rdf/xsd/duration.rb, line 96
def valid?
  !!value.match?(self.class.const_get(:GRAMMAR))
end
years() click to toggle source

Years

From the XQuery function [fn:years-from-duration](www.w3.org/TR/xpath-functions/#func-years-from-duration).

@return [Integer] @see www.w3.org/TR/xpath-functions/#func-years-from-duration

# File lib/rdf/xsd/duration.rb, line 187
def years; Integer.new(to_h[:yr] * (to_h[:si] ? -1 : 1)); end

Private Instance Methods

parse(value) click to toggle source

Reverse convert from XSD version of duration XSD allows -P1111Y22M33DT44H55M66.666S with any combination in regular order We assume 1M == 30D, but are out of spec in this regard We only output up to hours

@param [String] value XSD formatted duration @return [Duration]

# File lib/rdf/xsd/duration.rb, line 237
def parse(value)
  return [0, 0] unless md = value.to_s.match(GRAMMAR)

  months  = md[:yr].to_i * 12 + md[:mo].to_i
  seconds = md[:da].to_i * 3600 * 24 +
            md[:hr].to_i * 3600 +
            md[:mi].to_i * 60 +
            md[:se].to_f

  if md[:si]
    if months != 0
      months = -months
    else
      seconds = -seconds
    end
  end

  [months, seconds]
end
sec_str() click to toggle source
# File lib/rdf/xsd/duration.rb, line 257
def sec_str
  sec = @object.last.abs % 60
  ((sec.truncate == sec ? "%d" : "%2.3f") % sec).sub(/(\.[1-9]+)0+$/, '\1')
end