class ISO8601::Time

A Time representation

@example

t = Time.new('10:11:12')
t = Time.new('T10:11:12.5Z')
t.hour # => 10
t.minute # => 11
t.second # => 12.5
t.zone # => '+00:00'

Attributes

atoms[R]

The original atoms

second[R]

The second atom

separator[R]

The separator used in the original ISO 8601 string.

Public Class Methods

new(input, base = ::Date.today) click to toggle source

@param [String] input The time pattern @param [Date] base The base date to determine the time

# File lib/iso8601/time.rb, line 38
def initialize(input, base = ::Date.today)
  @original = input
  @base = base
  @atoms = atomize(input)
  @time = compose(@atoms, @base)
  @second = @time.second + @time.second_fraction.to_f.round(1)
end

Public Instance Methods

+(other) click to toggle source

Forwards the time the given amount of seconds.

@param [Numeric] other The seconds to add

@return [ISO8601::Time] New time resulting of the addition

# File lib/iso8601/time.rb, line 74
def +(other)
  moment = @time.to_time.localtime(zone) + other.to_f.round(1)
  base = ::Date.parse(moment.strftime('%Y-%m-%d'))

  self.class.new(moment.strftime('T%H:%M:%S.%L%:z'), base)
end
-(other) click to toggle source

Backwards the date the given amount of seconds.

@param [Numeric] other The seconds to remove

@return [ISO8601::Time] New time resulting of the substraction

# File lib/iso8601/time.rb, line 87
def -(other)
  moment = @time.to_time.localtime(zone) - other.to_f.round(1)
  base = ::Date.parse(moment.strftime('%Y-%m-%d'))

  self.class.new(moment.strftime('T%H:%M:%S.%L%:z'), base)
end
==(other) click to toggle source

@param [#hash] other The contrast to compare against

@return [Boolean]

# File lib/iso8601/time.rb, line 50
def ==(other)
  (hash == other.hash)
end
eql?(other) click to toggle source

@param [#hash] other The contrast to compare against

@return [Boolean]

# File lib/iso8601/time.rb, line 58
def eql?(other)
  (hash == other.hash)
end
hash() click to toggle source

@return [Fixnum]

# File lib/iso8601/time.rb, line 64
def hash
  [atoms, self.class].hash
end
to_a() click to toggle source

Converts self to an array of atoms.

# File lib/iso8601/time.rb, line 104
def to_a
  [hour, minute, second, zone]
end
to_s() click to toggle source

Converts self to a time component representation.

# File lib/iso8601/time.rb, line 96
def to_s
  second_format = format((second % 1).zero? ? '%02d' : '%04.1f', second)

  format("T%02d:%02d:#{second_format}#{zone}", *atoms)
end

Private Instance Methods

atomize(input) click to toggle source

Splits the time component into valid atoms. Acceptable patterns: hh, hh:mm or hhmm and hh:mm:ss or hhmmss. Any form can be prepended by `T`.

@param [String] input

@return [Array<Integer, Float>]

rubocop:disable Metrics/AbcSize

# File lib/iso8601/time.rb, line 120
def atomize(input)
  _, time, zone = parse_timezone(input)
  _, hour, separator, minute, second = parse_time(time)

  raise(ISO8601::Errors::UnknownPattern, @original) if hour.nil?

  @separator = separator
  require_separator = require_separator(minute)

  hour = hour.to_i
  minute = minute.to_i
  second = parse_second(second)

  atoms = [hour, minute, second, zone].compact

  raise(ISO8601::Errors::UnknownPattern, @original) unless valid_zone?(zone, require_separator)

  atoms
end
compose(atoms, base) click to toggle source

Wraps ::DateNew.new to play nice with ArgumentError.

@param [Array<Integer>] atoms The time atoms. @param [::Date] base The base date to start computing time.

@return [::DateTime]

# File lib/iso8601/time.rb, line 183
def compose(atoms, base)
  ::DateTime.new(base.year, base.month, base.day, *atoms)
rescue ArgumentError
  raise ISO8601::Errors::RangeError, @original
end
parse_second(second) click to toggle source
# File lib/iso8601/time.rb, line 157
def parse_second(second)
  second.nil? ? 0.0 : second.tr(',', '.').to_f
end
parse_time(time) click to toggle source
# File lib/iso8601/time.rb, line 149
def parse_time(time)
  /^(?:
    (\d{2})(:?)(\d{2})\2(\d{2}(?:[.,]\d+)?) |
    (\d{2})(:?)(\d{2}) |
    (\d{2})
  )$/x.match(time).to_a.compact
end
parse_timezone(timezone) click to toggle source
# File lib/iso8601/time.rb, line 145
def parse_timezone(timezone)
  /^T?(.+?)(Z|[+-].+)?$/.match(timezone).to_a
end
require_separator(input) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/iso8601/time.rb, line 141
def require_separator(input)
  !input.nil?
end
valid_zone?(zone, require_separator) click to toggle source

@param [String] zone The timezone offset as Z or +-hh. @param [Boolean] require_separator Flag to determine if the separator

consistency check is required as patterns with only hour atom have no
separator but the timezone can.
# File lib/iso8601/time.rb, line 166
def valid_zone?(zone, require_separator)
  zone_regexp = /^(Z|[+-]\d{2}(?:(:?)\d{2})?)$/
  _, offset, separator = zone_regexp.match(zone).to_a.compact

  wrong_pattern = !zone.nil? && offset.nil?
  invalid_separators = zone.to_s.match(/^[+-]\d{2}:?\d{2}$/) && (@separator != separator) if require_separator

  !(wrong_pattern || invalid_separators)
end