2
# Copyright (c) 2006 Philip Ross
4
# Permission is hereby granted, free of charge, to any person obtaining a copy
5
# of this software and associated documentation files (the "Software"), to deal
6
# in the Software without restriction, including without limitation the rights
7
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
# copies of the Software, and to permit persons to whom the Software is
9
# furnished to do so, subject to the following conditions:
11
# The above copyright notice and this permission notice shall be included in all
12
# copies or substantial portions of the Software.
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
require 'tzinfo/offset_rationals'
28
# Used by TZInfo internally to represent either a Time, DateTime or integer
29
# timestamp (seconds since 1970-01-01 00:00:00).
30
class TimeOrDateTime #:nodoc:
33
# Constructs a new TimeOrDateTime. timeOrDateTime can be a Time, DateTime
34
# or an integer. If using a Time or DateTime, any time zone information is
36
def initialize(timeOrDateTime)
41
if timeOrDateTime.is_a?(Time)
42
@time = timeOrDateTime
43
@time = Time.utc(@time.year, @time.mon, @time.mday, @time.hour, @time.min, @time.sec) unless @time.zone == 'UTC'
45
elsif timeOrDateTime.is_a?(DateTime)
46
@datetime = timeOrDateTime
47
@datetime = @datetime.new_offset(0) unless @datetime.offset == 0
50
@timestamp = timeOrDateTime.to_i
55
# Returns the time as a Time.
59
@time = Time.at(@timestamp).utc
61
@time = Time.utc(year, mon, mday, hour, min, sec)
68
# Returns the time as a DateTime.
71
@datetime = DateTime.new(year, mon, mday, hour, min, sec)
77
# Returns the time as an integer timestamp.
80
@timestamp = to_time.to_i
86
# Returns the time as the original time passed to new.
91
# Returns a string representation of the TimeOrDateTime.
95
elsif @orig.is_a?(DateTime)
96
"DateTime: #{@orig.to_s}"
98
"Timestamp: #{@orig.to_s}"
102
# Returns internal object state as a programmer-readable string.
104
"#<#{self.class}: #{@orig.inspect}>"
118
# Returns the month of the year (1..12).
130
# Returns the day of the month (1..n).
142
# Returns the hour of the day (0..23).
153
# Returns the minute of the hour (0..59).
164
# Returns the second of the minute (0..60). (60 for a leap second).
175
# Compares this TimeOrDateTime with another Time, DateTime, integer
176
# timestamp or TimeOrDateTime. Returns -1, 0 or +1 depending whether the
177
# receiver is less than, equal to, or greater than timeOrDateTime.
179
# Milliseconds and smaller units are ignored in the comparison.
180
def <=>(timeOrDateTime)
181
if timeOrDateTime.is_a?(TimeOrDateTime)
182
orig = timeOrDateTime.to_orig
184
if @orig.is_a?(DateTime) || orig.is_a?(DateTime)
185
# If either is a DateTime, assume it is there for a reason
187
to_datetime <=> timeOrDateTime.to_datetime
188
elsif orig.is_a?(Time)
189
to_time <=> timeOrDateTime.to_time
191
to_i <=> timeOrDateTime.to_i
193
elsif @orig.is_a?(DateTime) || timeOrDateTime.is_a?(DateTime)
194
# If either is a DateTime, assume it is there for a reason
196
to_datetime <=> TimeOrDateTime.wrap(timeOrDateTime).to_datetime
197
elsif timeOrDateTime.is_a?(Time)
198
to_time <=> timeOrDateTime
200
to_i <=> timeOrDateTime.to_i
204
# Adds a number of seconds to the TimeOrDateTime. Returns a new
205
# TimeOrDateTime, preserving what the original constructed type was.
206
# If the original type is a Time and the resulting calculation goes out of
207
# range for Times, then an exception will be raised by the Time class.
212
if @orig.is_a?(DateTime)
213
TimeOrDateTime.new(@orig + OffsetRationals.rational_for_offset(seconds))
215
# + defined for Time and integer timestamps
216
TimeOrDateTime.new(@orig + seconds)
221
# Subtracts a number of seconds from the TimeOrDateTime. Returns a new
222
# TimeOrDateTime, preserving what the original constructed type was.
223
# If the original type is a Time and the resulting calculation goes out of
224
# range for Times, then an exception will be raised by the Time class.
229
# Similar to the + operator, but for cases where adding would cause a
230
# timestamp or time to go out of the allowed range, converts to a DateTime
231
# based TimeOrDateTime.
232
def add_with_convert(seconds)
236
if @orig.is_a?(DateTime)
237
TimeOrDateTime.new(@orig + OffsetRationals.rational_for_offset(seconds))
239
# A Time or timestamp.
240
result = to_i + seconds
242
if result < 0 || result > 2147483647
243
result = TimeOrDateTime.new(to_datetime + OffsetRationals.rational_for_offset(seconds))
245
result = TimeOrDateTime.new(@orig + seconds)
251
# Returns true if todt represents the same time and was originally
252
# constructed with the same type (DateTime, Time or timestamp) as this
255
todt.respond_to?(:to_orig) && to_orig.eql?(todt.to_orig)
258
# Returns a hash of this TimeOrDateTime.
263
# If no block is given, returns a TimeOrDateTime wrapping the given
264
# timeOrDateTime. If a block is specified, a TimeOrDateTime is constructed
265
# and passed to the block. The result of the block must be a TimeOrDateTime.
266
# to_orig will be called on the result and the result of to_orig will be
269
# timeOrDateTime can be a Time, DateTime, integer timestamp or TimeOrDateTime.
270
# If a TimeOrDateTime is passed in, no new TimeOrDateTime will be constructed,
271
# the passed in value will be used.
272
def self.wrap(timeOrDateTime)
273
t = timeOrDateTime.is_a?(TimeOrDateTime) ? timeOrDateTime : TimeOrDateTime.new(timeOrDateTime)
278
if timeOrDateTime.is_a?(TimeOrDateTime)
280
elsif timeOrDateTime.is_a?(Time)
282
elsif timeOrDateTime.is_a?(DateTime)