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.
Constants
- DATATYPE
- GRAMMAR
Public Class Methods
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)
# 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
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
# 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
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
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
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
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
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
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
# File lib/rdf/xsd/duration.rb, line 141 def plural(v, str) "#{v} #{str}#{v.to_i == 1 ? '' : 's'}" if v end
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
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
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
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
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
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
# 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