Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 496 lines (441 sloc) 13.431 kb
a86377d @alloy Make MRTime.new work
authored
1 framework 'Foundation'
2
3 class MRTime < NSDate
4 ##
5 #
6 # Obligatory NSDate overrides
7 #
8
9 def init
10 if super
11 @offset = 0
12 self
13 end
14 end
15
16 def initWithTimeIntervalSinceReferenceDate(seconds)
17 if init
18 @offset = seconds
19 self
20 end
21 end
22
23 def timeIntervalSinceReferenceDate
24 @offset
25 end
26
27 ##
28 #
29 # API
30 #
31
1d06614 @alloy Make Time.at and Time#usec work
authored
32 class << self
33 def new
34 date
35 end
36 alias_method :now, :new
37
38 # call-seq:
39 # Time.at(time) => time
40 # Time.at(seconds_with_frac) => time
41 # Time.at(seconds, microseconds_with_frac) => time
42 #
43 # Creates a new time object with the value given by <i>time</i>,
44 # the given number of <i>seconds_with_frac</i>, or
45 # <i>seconds</i> and <i>microseconds_with_frac</i> from the Epoch.
46 # <i>seconds_with_frac</i> and <i>microseconds_with_frac</i>
47 # can be Integer, Float, Rational, or other Numeric.
48 # non-portable feature allows the offset to be negative on some systems.
49 #
50 # Time.at(0) #=> 1969-12-31 18:00:00 -0600
51 # Time.at(Time.at(0)) #=> 1969-12-31 18:00:00 -0600
52 # Time.at(946702800) #=> 1999-12-31 23:00:00 -0600
53 # Time.at(-284061600) #=> 1960-12-31 00:00:00 -0600
54 # Time.at(946684800.2).usec #=> 200000
55 # Time.at(946684800, 123456.789).nsec #=> 123456789
56 def at(*x)
57 x = x.first if x.size == 1
58 case x
59 when Numeric
60 dateWithTimeIntervalSince1970(x)
61 when NSDate
62 dateWithTimeIntervalSinceReferenceDate(x.timeIntervalSinceReferenceDate)
63 when Array
64 sec, usec = x
65 interval = sec + (usec.to_f / 1_000_000)
66 dateWithTimeIntervalSince1970(interval)
67 end
68 end
dd57d1d @alloy Stash work on MRTime.local
authored
69
70 # call-seq:
71 # Time.local(year) => time
72 # Time.local(year, month) => time
73 # Time.local(year, month, day) => time
74 # Time.local(year, month, day, hour) => time
75 # Time.local(year, month, day, hour, min) => time
76 # Time.local(year, month, day, hour, min, sec_with_frac) => time
77 # Time.local(year, month, day, hour, min, sec, usec_with_frac) => time
78 # Time.local(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
79 # Time.mktime(year) => time
80 # Time.mktime(year, month) => time
81 # Time.mktime(year, month, day) => time
82 # Time.mktime(year, month, day, hour) => time
83 # Time.mktime(year, month, day, hour, min) => time
84 # Time.mktime(year, month, day, hour, min, sec_with_frac) => time
85 # Time.mktime(year, month, day, hour, min, sec, usec_with_frac) => time
86 # Time.mktime(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
87 #
88 # Same as <code>Time::gm</code>, but interprets the values in the
89 # local time zone.
90 #
91 # Time.local(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 -0600
92 def local(*args)
93 case args.size
94 when 6
95 year, month, day, hour, min, sec_with_frac = args
96
97 components = NSDateComponents.new
98 components.year = year
99 components.month = month
100 components.day = day
101 components.hour = hour
102 components.minute = min
103
104 calendar = NSCalendar.alloc.initWithCalendarIdentifier(NSGregorianCalendar)
105 date = calendar.dateFromComponents(components)
106
107 date = dateWithTimeIntervalSinceReferenceDate(date.timeIntervalSinceReferenceDate + sec_with_frac)
108 date.timeZone = timeZoneFromEnv
109 date
110 end
111 end
112
113 private
114
115 def timeZoneFromEnv
116 zone = ENV['TZ'].match(/^[A-Z]+/)[0]
117 p zone
118 res = NSTimeZone.timeZoneWithAbbreviation(zone)
119 p res
120 res
121 end
a86377d @alloy Make MRTime.new work
authored
122 end
123 end
1d06614 @alloy Make Time.at and Time#usec work
authored
124
125 module MRTimeAPI
dd57d1d @alloy Stash work on MRTime.local
authored
126 # TODO: this should not be visible, I guess
127 attr_accessor :timeZone
128
b568bca @alloy Make #+ work, more or less.
authored
129 include Comparable
130
131 # call-seq:
132 # time <=> other_time => -1, 0, +1
1d06614 @alloy Make Time.at and Time#usec work
authored
133 #
b568bca @alloy Make #+ work, more or less.
authored
134 # Comparison---Compares <i>time</i> with <i>other_time</i>.
135 #
136 # t = Time.now #=> 2007-11-19 08:12:12 -0600
137 # t2 = t + 2592000 #=> 2007-12-19 08:12:12 -0600
138 # t <=> t2 #=> -1
139 # t2 <=> t #=> 1
140 #
141 # t = Time.now #=> 2007-11-19 08:13:38 -0600
142 # t2 = t + 0.1 #=> 2007-11-19 08:13:38 -0600
143 # t.nsec #=> 98222999
144 # t2.nsec #=> 198222999
145 # t <=> t2 #=> -1
146 # t2 <=> t #=> 1
147 # t <=> t #=> 0
148 def <=>(time)
149 # timeIntervalSinceReferenceDate <=> time.timeIntervalSinceReferenceDate if time.is_a?(NSDate)
150 compare(time) if time.is_a?(NSDate)
151 end
152
779b319 @alloy Make #eql? and #== work
authored
153 def eql?(other)
154 compare(other) == NSOrderedSame
155 end
156 alias_method :==, :eql?
08ff038 @alloy Make #- work
authored
157
158 # call-seq:
159 # time - other_time => float
160 # time - numeric => time
1d06614 @alloy Make Time.at and Time#usec work
authored
161 #
08ff038 @alloy Make #- work
authored
162 # Difference---Returns a new time that represents the difference
163 # between two times, or subtracts the given number of seconds in
164 # <i>numeric</i> from <i>time</i>.
165 #
166 # t = Time.now #=> 2007-11-19 08:23:10 -0600
167 # t2 = t + 2592000 #=> 2007-12-19 08:23:10 -0600
168 # t2 - t #=> 2592000.0
169 # t2 - 2592000 #=> 2007-11-19 08:23:10 -0600
170 def -(x)
171 if x.is_a?(NSDate)
172 timeIntervalSinceReferenceDate - x.timeIntervalSinceReferenceDate
173 else
174 unless x.is_a?(Numeric)
175 if x && x.respond_to?(:to_r)
176 x = x.to_r # TODO: maybe we should skip this
177 else
178 raise TypeError
179 end
180 end
181 self.class.dateWithTimeIntervalSinceReferenceDate(timeIntervalSinceReferenceDate - x.to_f)
182 end
183 end
b568bca @alloy Make #+ work, more or less.
authored
184
185 # call-seq:
186 # time + numeric => time
1d06614 @alloy Make Time.at and Time#usec work
authored
187 #
b568bca @alloy Make #+ work, more or less.
authored
188 # Addition---Adds some number of seconds (possibly fractional) to
189 # <i>time</i> and returns that value as a new time.
190 #
191 # t = Time.now #=> 2007-11-19 08:22:21 -0600
192 # t + (60 * 60 * 24) #=> 2007-11-20 08:22:21 -0600
193 def +(x)
194 unless x.is_a?(Numeric)
195 if x && x.respond_to?(:to_r)
196 x = x.to_r # TODO: maybe we should skip this
197 else
198 raise TypeError
199 end
200 end
201 self.class.dateWithTimeIntervalSinceReferenceDate(timeIntervalSinceReferenceDate + x.to_f)
202 end
203
1d06614 @alloy Make Time.at and Time#usec work
authored
204 # # Return a new Date object that is +n+ months earlier than
205 # # the current one.
206 # #
207 # # If the day-of-the-month of the current Date is greater
208 # # than the last day of the target month, the day-of-the-month
209 # # of the returned Date will be the last day of the target month.
210 # def <<(n)
211 # date_with_offset(-n, :month)
212 # end
213 #
214 # # Return a new Date object that is +n+ months later than
215 # # the current one.
216 # #
217 # # If the day-of-the-month of the current Date is greater
218 # # than the last day of the target month, the day-of-the-month
219 # # of the returned Date will be the last day of the target month.
220 # def >>(n)
221 # date_with_offset(n, :month)
222 # end
223
224 BC = 0
225 AD = 1
226
227 def year
228 components.era == BC ? -(components.year - 1) : components.year
229 end
230
231 def month
232 components.month
233 end
234 alias_method :mon, :month
235
236 def day
237 components.day
238 end
239 alias_method :mday, :day
240
241 # Get the week day of this date. Sunday is day-of-week 0;
242 # Saturday is day-of-week 6.
243 def wday
244 components.weekday - 1
245 end
246
bdd445e @alloy Make #yday work
authored
247 # call-seq:
248 # time.yday => fixnum
249 #
250 # Returns an integer representing the day of the year, 1..366.
251 #
252 # t = Time.now #=> 2007-11-19 08:32:31 -0600
253 # t.yday #=> 323
254 def yday
255 calendar.ordinalityOfUnit(NSDayCalendarUnit, inUnit: NSYearCalendarUnit, forDate: self)
256 end
257
1d06614 @alloy Make Time.at and Time#usec work
authored
258 def hour
259 components.hour
260 end
261
024c2f1 @alloy Make #day, #mday, #hour, #min, and #sec work
authored
262 def min
1d06614 @alloy Make Time.at and Time#usec work
authored
263 components.minute
264 end
024c2f1 @alloy Make #day, #mday, #hour, #min, and #sec work
authored
265 alias_method :minute, :min
1d06614 @alloy Make Time.at and Time#usec work
authored
266
024c2f1 @alloy Make #day, #mday, #hour, #min, and #sec work
authored
267 def sec
1d06614 @alloy Make Time.at and Time#usec work
authored
268 components.second
269 end
024c2f1 @alloy Make #day, #mday, #hour, #min, and #sec work
authored
270 alias_method :second, :sec
1d06614 @alloy Make Time.at and Time#usec work
authored
271
17b5627 @alloy Make #nsec and #tv_nsec work, somewhat.
authored
272 # TODO: this is hardly professional!
1d06614 @alloy Make Time.at and Time#usec work
authored
273 def usec
274 interval = timeIntervalSince1970
275 decimals = interval - interval.to_i
276 (decimals * 1_000_000).round
277 end
01c8c9d @alloy Make #tv_usec work, somewhat
authored
278 alias_method :tv_usec, :usec
1d06614 @alloy Make Time.at and Time#usec work
authored
279
17b5627 @alloy Make #nsec and #tv_nsec work, somewhat.
authored
280 # TODO: this is hardly professional!
281 def nsec
282 usec * 1000
283 end
284 alias_method :tv_nsec, :nsec
285
b568bca @alloy Make #+ work, more or less.
authored
286 def to_i
287 timeIntervalSince1970.round
288 end
ac95af1 @alloy Make #tv_sec work
authored
289 alias_method :tv_sec, :to_i
b568bca @alloy Make #+ work, more or less.
authored
290
ab0e25b @alloy Make #to_f work
authored
291 def to_f
292 timeIntervalSince1970
293 end
294
dd57d1d @alloy Stash work on MRTime.local
authored
295 def to_r
296
297 end
298
2da4707 @alloy Make #succ work
authored
299 # call-seq:
300 # time.succ => new_time
301 #
302 # Return a new time object, one second later than <code>time</code>.
303 #
304 # t = Time.now #=> 2007-11-19 08:23:57 -0600
305 # t.succ #=> 2007-11-19 08:23:58 -0600
306 def succ
307 self.class.dateWithTimeIntervalSinceReferenceDate(timeIntervalSinceReferenceDate + 1)
308 end
309
d6c9b23 @alloy Make #sunday? through #saturday? work.
authored
310 ##
311 #
312 # Specific day sugar
313 #
314
315 # call-seq:
316 # time.sunday? => true or false
317 #
318 # Returns <code>true</code> if <i>time</i> represents Sunday.
319 #
320 # t = Time.local(1990, 4, 1) #=> 1990-04-01 00:00:00 -0600
321 # t.sunday? #=> true
322 def sunday?
323 wday == 0
324 end
325
326 # call-seq:
327 # time.monday? => true or false
328 #
329 # Returns <code>true</code> if <i>time</i> represents Monday.
330 #
331 # t = Time.local(2003, 8, 4) #=> 2003-08-04 00:00:00 -0500
332 # p t.monday? #=> true
333 def monday?
334 wday == 1
335 end
336
337 # call-seq:
338 # time.tuesday? => true or false
339 #
340 # Returns <code>true</code> if <i>time</i> represents Tuesday.
341 #
342 # t = Time.local(1991, 2, 19) #=> 1991-02-19 00:00:00 -0600
343 # p t.tuesday? #=> true
344 def tuesday?
345 wday == 2
346 end
347
348 # call-seq:
349 # time.wednesday? => true or false
350 #
351 # Returns <code>true</code> if <i>time</i> represents Wednesday.
352 #
353 # t = Time.local(1993, 2, 24) #=> 1993-02-24 00:00:00 -0600
354 # p t.wednesday? #=> true
355 def wednesday?
356 wday == 3
357 end
358
359 # call-seq:
360 # time.thursday? => true or false
361 #
362 # Returns <code>true</code> if <i>time</i> represents Thursday.
363 #
364 # t = Time.local(1995, 12, 21) #=> 1995-12-21 00:00:00 -0600
365 # p t.thursday? #=> true
366 def thursday?
367 wday == 4
368 end
369
370 # call-seq:
371 # time.friday? => true or false
372 #
373 # Returns <code>true</code> if <i>time</i> represents Friday.
374 #
375 # t = Time.local(1987, 12, 18) #=> 1987-12-18 00:00:00 -0600
376 # t.friday? #=> true
377 def friday?
378 wday == 5
379 end
380
381 # call-seq:
382 # time.saturday? => true or false
383 #
384 # Returns <code>true</code> if <i>time</i> represents Saturday.
385 #
386 # t = Time.local(2006, 6, 10) #=> 2006-06-10 00:00:00 -0500
387 # t.saturday? #=> true
388 def saturday?
389 wday == 6
390 end
391
1d06614 @alloy Make Time.at and Time#usec work
authored
392 # # TODO: lazy bastard
393 # def jd
394 # MRDate::JULIAN_DAY_FORMATTER.stringFromDate(self).to_i
395 # end
396 #
397 # # returns the julian day if it's a date before the specified calendar reform date
398 # def julian?
399 # timeIntervalSinceReferenceDate < @sg
400 # end
401 #
402 # # Step the current date forward +step+ days at a
403 # # time (or backward, if +step+ is negative) until
404 # # we reach +limit+ (inclusive), yielding the resultant
405 # # date at each step.
406 # def step(limit, step = 1)
407 # # unless block_given?
408 # # return to_enum(:step, limit, step)
409 # # end
410 # da = self
411 # op = %w(- <= >=)[step <=> 0]
412 # while da.send(op, limit)
413 # yield da
414 # da += step
415 # end
416 # self
417 # end
418 #
419 # # Step forward one day at a time until we reach +max+
420 # # (inclusive), yielding each date as we go.
421 # def upto(max, &block) # :yield: date
422 # step(max, +1, &block)
423 # end
424 #
425 # # Step backward one day at a time until we reach +min+
426 # # (inclusive), yielding each date as we go.
427 # def downto(min, &block) # :yield: date
428 # step(min, -1, &block)
429 # end
430 #
431 # # TODO: Not sure what hash is being returned by MacRuby, but it seems to work already...
432 # # def hash
433 # # jd.hash
434 # # end
435 #
436 # ##
437 # #
438 # # String methods
439 # #
440 #
441 # # TODO: possibly add something like the following, which could be much faster
442 # #
443 # # alias_method :__original_strftime, :strftime
444 # # def strftime(format = '%F', use_ruby_strftime = true)
445 # # if use_ruby_strftime
446 # # __original_strftime(format)
447 # # else
448 # # descriptionWithCalendarFormat(format, timeZone: nil, locale: nil)
449 # # end
450 # # end
451
452 def to_s
453 # TODO this breaks the minus spec: strftime
dd57d1d @alloy Stash work on MRTime.local
authored
454 if @timeZone
455 # offset = @timeZone.secondsFromGMT.abs
456 offset = @timeZone.secondsFromGMTForDate(self).abs
457 p offset
458 hours = offset / 3600
459 p hours
460 minutes = hours % 60
461 p minutes
462
463 end
1d06614 @alloy Make Time.at and Time#usec work
authored
464 format "#{year}-%02d-%02d %02d:%02d:%02d +0200", month, day, hour, minute, second
465 end
466 alias_method :inspect, :to_s
467
468 private
469
470 GREGORIAN_CALENDAR = NSCalendar.alloc.initWithCalendarIdentifier(NSGregorianCalendar)
471
472 def calendar
473 GREGORIAN_CALENDAR
474 end
475
476 PARSE_COMPONENTS = NSEraCalendarUnit | NSYearCalendarUnit |
477 NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit |
478 NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit
479
480 def components
481 calendar.components(PARSE_COMPONENTS, fromDate: self)
482 end
483
b568bca @alloy Make #+ work, more or less.
authored
484 # asserts x is a numeric and assigns it to the method type, eg year, month, day
485 def date_with_offset(x, type)
486 raise TypeError, "expected numeric" unless x.is_a?(Numeric)
487
488 offset = NSDateComponents.new
489 offset.send("#{type}=", x)
490 calendar.dateByAddingComponents(offset, toDate: self, options: 0)
491 end
1d06614 @alloy Make Time.at and Time#usec work
authored
492 end
493
494 class NSDate
495 include MRTimeAPI
496 end
Something went wrong with that request. Please try again.