Froze rails gems
[depot.git] / vendor / rails / activesupport / lib / active_support / vendor / tzinfo-0.3.12 / tzinfo / time_or_datetime.rb
1 #--
2 # Copyright (c) 2006 Philip Ross
3 #
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:
10 #
11 # The above copyright notice and this permission notice shall be included in all
12 # copies or substantial portions of the Software.
13 #
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
20 # THE SOFTWARE.
21 #++
22
23 require 'date'
24 require 'time'
25 require 'tzinfo/offset_rationals'
26
27 module TZInfo
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:
31 include Comparable
32
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
35 # ignored.
36 def initialize(timeOrDateTime)
37 @time = nil
38 @datetime = nil
39 @timestamp = nil
40
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'
44 @orig = @time
45 elsif timeOrDateTime.is_a?(DateTime)
46 @datetime = timeOrDateTime
47 @datetime = @datetime.new_offset(0) unless @datetime.offset == 0
48 @orig = @datetime
49 else
50 @timestamp = timeOrDateTime.to_i
51 @orig = @timestamp
52 end
53 end
54
55 # Returns the time as a Time.
56 def to_time
57 unless @time
58 if @timestamp
59 @time = Time.at(@timestamp).utc
60 else
61 @time = Time.utc(year, mon, mday, hour, min, sec)
62 end
63 end
64
65 @time
66 end
67
68 # Returns the time as a DateTime.
69 def to_datetime
70 unless @datetime
71 @datetime = DateTime.new(year, mon, mday, hour, min, sec)
72 end
73
74 @datetime
75 end
76
77 # Returns the time as an integer timestamp.
78 def to_i
79 unless @timestamp
80 @timestamp = to_time.to_i
81 end
82
83 @timestamp
84 end
85
86 # Returns the time as the original time passed to new.
87 def to_orig
88 @orig
89 end
90
91 # Returns a string representation of the TimeOrDateTime.
92 def to_s
93 if @orig.is_a?(Time)
94 "Time: #{@orig.to_s}"
95 elsif @orig.is_a?(DateTime)
96 "DateTime: #{@orig.to_s}"
97 else
98 "Timestamp: #{@orig.to_s}"
99 end
100 end
101
102 # Returns internal object state as a programmer-readable string.
103 def inspect
104 "#<#{self.class}: #{@orig.inspect}>"
105 end
106
107 # Returns the year.
108 def year
109 if @time
110 @time.year
111 elsif @datetime
112 @datetime.year
113 else
114 to_time.year
115 end
116 end
117
118 # Returns the month of the year (1..12).
119 def mon
120 if @time
121 @time.mon
122 elsif @datetime
123 @datetime.mon
124 else
125 to_time.mon
126 end
127 end
128 alias :month :mon
129
130 # Returns the day of the month (1..n).
131 def mday
132 if @time
133 @time.mday
134 elsif @datetime
135 @datetime.mday
136 else
137 to_time.mday
138 end
139 end
140 alias :day :mday
141
142 # Returns the hour of the day (0..23).
143 def hour
144 if @time
145 @time.hour
146 elsif @datetime
147 @datetime.hour
148 else
149 to_time.hour
150 end
151 end
152
153 # Returns the minute of the hour (0..59).
154 def min
155 if @time
156 @time.min
157 elsif @datetime
158 @datetime.min
159 else
160 to_time.min
161 end
162 end
163
164 # Returns the second of the minute (0..60). (60 for a leap second).
165 def sec
166 if @time
167 @time.sec
168 elsif @datetime
169 @datetime.sec
170 else
171 to_time.sec
172 end
173 end
174
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.
178 #
179 # Milliseconds and smaller units are ignored in the comparison.
180 def <=>(timeOrDateTime)
181 if timeOrDateTime.is_a?(TimeOrDateTime)
182 orig = timeOrDateTime.to_orig
183
184 if @orig.is_a?(DateTime) || orig.is_a?(DateTime)
185 # If either is a DateTime, assume it is there for a reason
186 # (i.e. for range).
187 to_datetime <=> timeOrDateTime.to_datetime
188 elsif orig.is_a?(Time)
189 to_time <=> timeOrDateTime.to_time
190 else
191 to_i <=> timeOrDateTime.to_i
192 end
193 elsif @orig.is_a?(DateTime) || timeOrDateTime.is_a?(DateTime)
194 # If either is a DateTime, assume it is there for a reason
195 # (i.e. for range).
196 to_datetime <=> TimeOrDateTime.wrap(timeOrDateTime).to_datetime
197 elsif timeOrDateTime.is_a?(Time)
198 to_time <=> timeOrDateTime
199 else
200 to_i <=> timeOrDateTime.to_i
201 end
202 end
203
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.
208 def +(seconds)
209 if seconds == 0
210 self
211 else
212 if @orig.is_a?(DateTime)
213 TimeOrDateTime.new(@orig + OffsetRationals.rational_for_offset(seconds))
214 else
215 # + defined for Time and integer timestamps
216 TimeOrDateTime.new(@orig + seconds)
217 end
218 end
219 end
220
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.
225 def -(seconds)
226 self + (-seconds)
227 end
228
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)
233 if seconds == 0
234 self
235 else
236 if @orig.is_a?(DateTime)
237 TimeOrDateTime.new(@orig + OffsetRationals.rational_for_offset(seconds))
238 else
239 # A Time or timestamp.
240 result = to_i + seconds
241
242 if result < 0 || result > 2147483647
243 result = TimeOrDateTime.new(to_datetime + OffsetRationals.rational_for_offset(seconds))
244 else
245 result = TimeOrDateTime.new(@orig + seconds)
246 end
247 end
248 end
249 end
250
251 # Returns true if todt represents the same time and was originally
252 # constructed with the same type (DateTime, Time or timestamp) as this
253 # TimeOrDateTime.
254 def eql?(todt)
255 todt.respond_to?(:to_orig) && to_orig.eql?(todt.to_orig)
256 end
257
258 # Returns a hash of this TimeOrDateTime.
259 def hash
260 @orig.hash
261 end
262
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
267 # returned.
268 #
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)
274
275 if block_given?
276 t = yield t
277
278 if timeOrDateTime.is_a?(TimeOrDateTime)
279 t
280 elsif timeOrDateTime.is_a?(Time)
281 t.to_time
282 elsif timeOrDateTime.is_a?(DateTime)
283 t.to_datetime
284 else
285 t.to_i
286 end
287 else
288 t
289 end
290 end
291 end
292 end