| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| module Arrow |
| class Time |
| attr_reader :unit |
| attr_reader :value |
| def initialize(unit, value) |
| @unit = unit |
| @value = value |
| @unconstructed = false |
| end |
| |
| def ==(other) |
| other.is_a?(self.class) and |
| positive? == other.positive? and |
| hour == other.hour and |
| minute == other.minute and |
| second == other.second and |
| nano_second == other.nano_second |
| end |
| |
| def cast(target_unit) |
| return self.class.new(@unit, @value) if @unit == target_unit |
| |
| target_value = (hour * 60 * 60) + (minute * 60) + second |
| case target_unit |
| when TimeUnit::MILLI |
| target_value *= 1000 |
| target_value += nano_second / 1000 / 1000 |
| when TimeUnit::MICRO |
| target_value *= 1000 * 1000 |
| target_value += nano_second / 1000 |
| when TimeUnit::NANO |
| target_value *= 1000 * 1000 * 1000 |
| target_value += nano_second |
| end |
| target_value = -target_value if negative? |
| self.class.new(target_unit, target_value) |
| end |
| |
| def to_f |
| case @unit |
| when TimeUnit::SECOND |
| @value.to_f |
| when TimeUnit::MILLI |
| @value.to_f / 1000.0 |
| when TimeUnit::MICRO |
| @value.to_f / 1000.0 / 1000.0 |
| when TimeUnit::NANO |
| @value.to_f / 1000.0 / 1000.0 / 1000.0 |
| end |
| end |
| |
| def positive? |
| @value.positive? |
| end |
| |
| def negative? |
| @value.negative? |
| end |
| |
| def hour |
| unconstruct |
| @hour |
| end |
| |
| def minute |
| unconstruct |
| @minute |
| end |
| alias_method :min, :minute |
| |
| def second |
| unconstruct |
| @second |
| end |
| alias_method :sec, :second |
| |
| def nano_second |
| unconstruct |
| @nano_second |
| end |
| alias_method :nsec, :nano_second |
| |
| def to_s |
| unconstruct |
| if @nano_second.zero? |
| nano_second_string = "" |
| else |
| nano_second_string = (".%09d" % @nano_second).gsub(/0+\z/, "") |
| end |
| "%s%02d:%02d:%02d%s" % [ |
| @value.negative? ? "-" : "", |
| @hour, |
| @minute, |
| @second, |
| nano_second_string, |
| ] |
| end |
| |
| private |
| def unconstruct |
| return if @unconstructed |
| abs_value = @value.abs |
| case unit |
| when TimeUnit::SECOND |
| unconstruct_second(abs_value) |
| @nano_second = 0 |
| when TimeUnit::MILLI |
| unconstruct_second(abs_value / 1000) |
| @nano_second = (abs_value % 1000) * 1000 * 1000 |
| when TimeUnit::MICRO |
| unconstruct_second(abs_value / 1000 / 1000) |
| @nano_second = (abs_value % (1000 * 1000)) * 1000 |
| when TimeUnit::NANO |
| unconstruct_second(abs_value / 1000 / 1000 / 1000) |
| @nano_second = abs_value % (1000 * 1000 * 1000) |
| else |
| raise ArgumentError, "invalid unit: #{@unit.inspect}" |
| end |
| @unconstructed = true |
| end |
| |
| def unconstruct_second(abs_value_in_second) |
| if abs_value_in_second < 60 |
| hour = 0 |
| minute = 0 |
| second = abs_value_in_second |
| elsif abs_value_in_second < (60 * 60) |
| hour = 0 |
| minute = abs_value_in_second / 60 |
| second = abs_value_in_second % 60 |
| else |
| in_minute = abs_value_in_second / 60 |
| hour = in_minute / 60 |
| minute = in_minute % 60 |
| second = abs_value_in_second % 60 |
| end |
| @hour = hour |
| @minute = minute |
| @second = second |
| end |
| end |
| end |