Temporary tag for this failure. Updated CI spec coming.
[rbx.git] / kernel / core / moment.rb
blobcf51808c6ee5fdbea6e2eb9a24d900a9ee4f8f33
1 class Moment
3   def self.now
4     Moment.new(nil)
5   end
7   def self.at(time)
8     new(time)
9   end
11   def initialize(time)
12     if time
13       @utc   = time.respond_to?(:first) ? time.first : time
14       @micro = time.respond_to?(:last)  ? time.last  : 0
15     else
16       tv = Platform::POSIX::TimeVal.new
18       if 0 != Platform::POSIX.gettimeofday(tv.pointer, nil)
19         Errno.handle
20       end
22       @utc = tv[:tv_sec]
23       @micro = tv[:tv_usec]
25       tv.free
26     end
28     @local = @utc - Platform::POSIX.timezone
29     @time  = @local
30     @human = nil
31   end
33   def offset
34     @local - @utc
35   end
37   class HumanTime
38     def initialize(moment)
39       @moment = moment
40       # HACK. the 0 should be 1 if this Moment is during DST
41       @timezone = Platform::POSIX.tzname(0)
42     end
44     attr_accessor :micro
45     attr_accessor :second
46     attr_accessor :minute
47     attr_accessor :hour
49     Days = {
50       0 => :sunday,
51       1 => :monday,
52       2 => :tuesday,
53       3 => :wednesday,
54       4 => :thursday,
55       5 => :friday,
56       6 => :saturday
57     }
59     def from_jd(j)
60       @jd = j
62       # See http://www.hermetic.ch/cal_stud/jdn.htm
63       l = j + 68569
64       n = (4*l) / 146097
65       l = l - (146097*n+3) / 4
66       i = 4000 * (l+1) / 1461001
67       l = l - 1461 * i / 4  + 31
68       j = 80 * l / 2447
69       k = l-2447*j/80
70       l = j / 11
71       j = j + 2 - 12 * l
72       i = 100 * (n - 49) + i + l
74       @year = i
75       @month = j
76       @day = k
78       # HACK this only does gregorian weeks
79       @weekday = Days[(@jd + 1) % 7]
80     end
82     def leap?
83       @year % 4 == 0 && @year % 100 != 0 || @year % 400 == 0
84     end
86     # HACK these need to be locale specific tables
87     ShortWeekday = {
88       :monday => "Mon",
89       :tuesday => "Tue",
90       :wednesday => "Wed",
91       :thursday => "Thu",
92       :friday => "Fri",
93       :saturday => "Sat",
94       :sunday => "Sun"
95     }
97     def short_weekday
98       ShortWeekday[@weekday]
99     end
101     ShortMonth = {
102       1 => "Jan",
103       2 => "Feb",
104       3 => "Mar",
105       4 => "Apr",
106       5 => "May",
107       6 => "Jun",
108       7 => "Jul",
109       8 => "Aug",
110       9 => "Sep",
111       10 => "Oct",
112       11 => "Nov",
113       12 => "Dec"
114     }
116     def short_month
117       ShortMonth[@month]
118     end
120     def padded_day
121       if @day < 10
122         "0#{@day}"
123       else
124         @day.to_s
125       end
126     end
128     def padded_hour_24
129       if @hour < 10
130         "0#{@hour}"
131       else
132         @hour.to_s
133       end
134     end
136     def padded_minute
137       if @minute < 10
138         "0#{@minute}"
139       else
140         @minute.to_s
141       end
142     end
144     def padded_second
145       if @second < 10
146         "0#{@second}"
147       else
148         @second.to_s
149       end
150     end
152     def year
153       @year.to_s
154     end
156     def time_zone
157       @timezone
158     end
160     def time_offset
161       offset = @moment.offset / 3600
163       if offset.abs < 10
164         if offset < 0
165           "-0#{offset.abs}00"
166         else
167           "+0#{offset}00"
168         end
169       else
170         "#{offset}00"
171       end
172     end
173   end
175   EpochToMDJ = 40587
177   def to_human
178     # Cache it.
179     return @human if @human
181     s = @time % 86400
182     h = HumanTime.new(self)
184     h.micro  = @micro
185     h.second = (s % 60); s /= 60
186     h.minute = (s % 60); s /= 60
187     h.hour   = s
189     u = @time / 86400
191     @mjd = EpochToMDJ + u
193     # The julian day began an noon, not midnight.
194     jd = @mjd + 2400001
196     h.from_jd(jd)
198     @human = h
199     return h
200   end
202   FormatMethod = {
203     :A => :weekday,
204     :a => :short_weekday,
205     :B => :month,
206     :b => :short_month,
207     :C => :short_year,
208     :c => :locale_datetime,
209     :D => :mdy,
210     :d => :padded_day,
211     :e => :day,
212     :F => :ymd,
213     :g => :padded_short_commercial_year,
214     :G => :commercial_year,
215     :H => :padded_hour_24,
216     :h => :short_month,
217     :I => :padded_hour,
218     :j => :day_of_year,
219     :k => :bpadded_hour_24,
220     :l => :bpadded_hour,
221     :M => :padded_minute,
222     :m => :padded_month,
223     :n => :newline,
224     :p => :am_pm,
225     :R => :hour_minute,
226     :r => :hms_ap,
227     :S => :padded_second,
228     :s => :epoch,
229     :T => :hms,
230     :t => :tab,
231     :U => :week_from_sunday,
232     :u => :weekday,
233     :V => :week_from_monday,
234     :v => :unsupported,
235     :W => :unsupported,
236     :X => :locale_time,
237     :x => :locale_date,
238     :Y => :year,
239     :y => :padded_short_year,
240     :Z => :time_zone,
241     :z => :time_offset,
242     :'+' => :locale_dt2
243   }
245   def format(str)
246     h = to_human()
247     pattern = /%([#{FormatMethod.keys.join}])/o
248     str.gsub(pattern) do |which|
249       h.__send__ FormatMethod[$1.to_sym]
250     end
251   end
253   def to_s
254     if offset != 0
255       format "%a %b %d %H:%M:%S %Z %Y"
256     else
257       format "%a %b %d %H:%M:%S UTC %Y"
258     end
259   end
261   alias_method :inspect, :to_s