KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > runtime > builtin > meta > TimeMetaClass


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
15  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
16  * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
18  * Copyright (C) 2004 Joey Gibson <joey@joeygibson.com>
19  * Copyright (C) 2004 Charles O Nutter <headius@headius.com>
20  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
21  * Copyright (C) 2006 Thomas E Enebo <enebo@acm.org>
22  * Copyright (C) 2006 Ola Bini <ola.bini@ki.se>
23  * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
24  * Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the CPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the CPL, the GPL or the LGPL.
37  ***** END LICENSE BLOCK *****/

38 package org.jruby.runtime.builtin.meta;
39
40 import java.util.Calendar JavaDoc;
41 import java.util.Date JavaDoc;
42 import java.util.GregorianCalendar JavaDoc;
43 import java.util.TimeZone JavaDoc;
44
45 import org.jruby.Ruby;
46 import org.jruby.RubyClass;
47 import org.jruby.RubyFloat;
48 import org.jruby.RubyNumeric;
49 import org.jruby.RubyString;
50 import org.jruby.RubyTime;
51 import org.jruby.runtime.Arity;
52 import org.jruby.runtime.Block;
53 import org.jruby.runtime.ObjectAllocator;
54 import org.jruby.runtime.ThreadContext;
55 import org.jruby.runtime.builtin.IRubyObject;
56 import org.jruby.util.collections.SinglyLinkedList;
57
58 public class TimeMetaClass extends ObjectMetaClass {
59     public TimeMetaClass(Ruby runtime) {
60         super("Time", RubyTime.class, runtime.getObject(), TIME_ALLOCATOR);
61     }
62
63     public TimeMetaClass(String JavaDoc name, RubyClass superClass, ObjectAllocator allocator, SinglyLinkedList parentCRef) {
64         super(name, RubyTime.class, superClass, allocator, parentCRef);
65     }
66     
67     protected class TimeMeta extends Meta {
68         protected void initializeClass() {
69             includeModule(getRuntime().getModule("Comparable"));
70     
71             defineSingletonMethod("new", Arity.noArguments(), "s_new");
72             defineSingletonMethod("now", Arity.noArguments(), "s_new");
73             defineFastSingletonMethod("at", Arity.optional(), "new_at");
74             defineFastSingletonMethod("local", Arity.optional(), "new_local");
75             defineFastSingletonMethod("mktime", Arity.optional(), "new_local");
76             defineFastSingletonMethod("utc", Arity.optional(), "new_utc");
77             defineFastSingletonMethod("gm", Arity.optional(), "new_utc");
78             defineSingletonMethod("_load", Arity.singleArgument(), "s_load");
79             
80             // To override Comparable with faster String ones
81
defineFastMethod(">=", Arity.singleArgument(), "op_ge");
82             defineFastMethod(">", Arity.singleArgument(), "op_gt");
83             defineFastMethod("<=", Arity.singleArgument(), "op_le");
84             defineFastMethod("<", Arity.singleArgument(), "op_lt");
85             
86             defineFastMethod("===", Arity.singleArgument(), "same2");
87             defineFastMethod("+", Arity.singleArgument(), "op_plus");
88             defineFastMethod("-", Arity.singleArgument(), "op_minus");
89             defineFastMethod("<=>", Arity.singleArgument(), "op_cmp");
90             defineFastMethod("asctime", Arity.noArguments());
91             defineFastMethod("mday", Arity.noArguments());
92             defineAlias("day", "mday");
93             defineAlias("ctime", "asctime");
94             defineFastMethod("sec", Arity.noArguments());
95             defineFastMethod("min", Arity.noArguments());
96             defineFastMethod("hour", Arity.noArguments());
97             defineFastMethod("month", Arity.noArguments());
98             defineAlias("mon", "month");
99             defineFastMethod("year", Arity.noArguments());
100             defineFastMethod("wday", Arity.noArguments());
101             defineFastMethod("yday", Arity.noArguments());
102             defineFastMethod("isdst", Arity.noArguments());
103             defineAlias("dst?", "isdst");
104             defineFastMethod("zone", Arity.noArguments());
105             defineFastMethod("to_a", Arity.noArguments());
106             defineFastMethod("to_f", Arity.noArguments());
107             defineFastMethod("succ", Arity.noArguments());
108             defineFastMethod("to_i", Arity.noArguments());
109             defineFastMethod("to_s", Arity.noArguments());
110             defineFastMethod("inspect", Arity.noArguments());
111             defineFastMethod("strftime", Arity.singleArgument());
112             defineFastMethod("usec", Arity.noArguments());
113             defineAlias("tv_usec", "usec");
114             defineAlias("tv_sec", "to_i");
115             defineFastMethod("gmtime", Arity.noArguments());
116             defineAlias("utc", "gmtime");
117             defineFastMethod("gmt?", Arity.noArguments(), "gmt");
118             defineAlias("utc?", "gmt?");
119             defineAlias("gmtime?", "gmt?");
120             defineFastMethod("localtime", Arity.noArguments());
121             defineFastMethod("hash", Arity.noArguments());
122             defineFastMethod("initialize_copy", Arity.singleArgument());
123             defineMethod("_dump", Arity.optional(),"dump");
124             defineFastMethod("gmt_offset", Arity.noArguments());
125             defineAlias("gmtoff", "gmt_offset");
126             defineAlias("utc_offset", "gmt_offset");
127             defineFastMethod("getgm", Arity.noArguments());
128             defineFastMethod("getlocal", Arity.noArguments());
129             defineAlias("getutc", "getgm");
130         }
131     };
132     
133     protected Meta getMeta() {
134         return new TimeMeta();
135     }
136         
137     public RubyClass newSubClass(String JavaDoc name, SinglyLinkedList parentCRef) {
138         return new TimeMetaClass(name, this, TIME_ALLOCATOR, parentCRef);
139     }
140
141     private static ObjectAllocator TIME_ALLOCATOR = new ObjectAllocator() {
142         public IRubyObject allocate(Ruby runtime, RubyClass klass) {
143             RubyTime instance = new RubyTime(runtime, klass);
144
145             instance.setMetaClass(klass);
146
147             return instance;
148         }
149     };
150     
151     public IRubyObject s_new(Block block) {
152         RubyTime time = new RubyTime(getRuntime(), this);
153         GregorianCalendar JavaDoc cal = new GregorianCalendar JavaDoc();
154         cal.setTime(new Date JavaDoc());
155         time.setJavaCalendar(cal);
156         return time;
157     }
158
159     public IRubyObject new_at(IRubyObject[] args) {
160         int len = checkArgumentCount(args, 1, 2);
161
162         Calendar JavaDoc cal = Calendar.getInstance();
163         RubyTime time = new RubyTime(getRuntime(), this, cal);
164
165         if (args[0] instanceof RubyTime) {
166             ((RubyTime) args[0]).updateCal(cal);
167         } else {
168             long seconds = RubyNumeric.num2long(args[0]);
169             long millisecs = 0;
170             long microsecs = 0;
171             if (len > 1) {
172                 long tmp = RubyNumeric.num2long(args[1]);
173                 millisecs = tmp / 1000;
174                 microsecs = tmp % 1000;
175             }
176             else {
177                 // In the case of two arguments, MRI will discard the portion of
178
// the first argument after a decimal point (i.e., "floor").
179
// However in the case of a single argument, any portion after
180
// the decimal point is honored.
181
if (args[0] instanceof RubyFloat) {
182                     double dbl = ((RubyFloat) args[0]).getDoubleValue();
183                     long micro = (long) ((dbl - seconds) * 1000000);
184                     millisecs = micro / 1000;
185                     microsecs = micro % 1000;
186                 }
187             }
188             time.setUSec(microsecs);
189             cal.setTimeInMillis(seconds * 1000 + millisecs);
190         }
191
192         time.callInit(args, Block.NULL_BLOCK);
193
194         return time;
195     }
196
197     public RubyTime new_local(IRubyObject[] args) {
198         return createTime(args, false);
199     }
200
201     public RubyTime new_utc(IRubyObject[] args) {
202         return createTime(args, true);
203     }
204
205     public RubyTime s_load(IRubyObject from, Block block) {
206         return s_mload((RubyTime) s_new(block), from);
207     }
208
209     protected RubyTime s_mload(RubyTime time, IRubyObject from) {
210         Calendar JavaDoc calendar = Calendar.getInstance();
211         calendar.clear();
212         calendar.setTimeZone(TimeZone.getTimeZone(RubyTime.UTC));
213         byte[] fromAsBytes = null;
214         fromAsBytes = from.convertToString().getBytes();
215         if(fromAsBytes.length != 8) {
216             throw getRuntime().newTypeError("marshaled time format differ");
217         }
218         int p=0;
219         int s=0;
220         for(int i = 0; i < 4; i++) {
221             p |= ((int)fromAsBytes[i] & 0xFF) << (8*i);
222         }
223         for(int i = 4; i < 8; i++) {
224             s |= ((int)fromAsBytes[i] & 0xFF) << (8*(i-4));
225         }
226         if((p & (1<<31)) == 0) {
227             calendar.setTimeInMillis(p * 1000L + s);
228         } else {
229             p &= ~(1<<31);
230             calendar.set(Calendar.YEAR,((p >>> 14) & 0xFFFF)+1900);
231             calendar.set(Calendar.MONTH,((p >>> 10) & 0xF));
232             calendar.set(Calendar.DAY_OF_MONTH,((p >>> 5) & 0x1F));
233             calendar.set(Calendar.HOUR_OF_DAY,(p & 0x1F));
234             calendar.set(Calendar.MINUTE,((s >>> 26) & 0x3F));
235             calendar.set(Calendar.SECOND,((s >>> 20) & 0x3F));
236             calendar.set(Calendar.MILLISECOND,(s & 0xFFFFF));
237         }
238         time.setJavaCalendar(calendar);
239         return time;
240     }
241     
242     private static final String JavaDoc[] months = {"jan", "feb", "mar", "apr", "may", "jun",
243                                             "jul", "aug", "sep", "oct", "nov", "dec"};
244     private static final long[] time_min = {1, 0, 0, 0, 0};
245     private static final long[] time_max = {31, 23, 59, 60, Long.MAX_VALUE};
246
247     private RubyTime createTime(IRubyObject[] args, boolean gmt) {
248         int len = 6;
249         if (args.length == 10) {
250             args = new IRubyObject[] { args[5], args[4], args[3], args[2], args[1], args[0] };
251         } else {
252             // MRI accepts additional wday argument which appears to be ignored.
253
len = checkArgumentCount(args, 1, 8);
254         }
255         ThreadContext tc = getRuntime().getCurrentContext();
256         if(!(args[0] instanceof RubyNumeric)) {
257             args[0] = args[0].callMethod(tc,"to_i");
258         }
259         int year = (int)RubyNumeric.num2long(args[0]);
260         int month = 0;
261         
262         if (len > 1) {
263             if (!args[1].isNil()) {
264                 if (args[1] instanceof RubyString) {
265                     month = -1;
266                     for (int i = 0; i < 12; i++) {
267                         if (months[i].equalsIgnoreCase(args[1].toString())) {
268                             month = i;
269                         }
270                     }
271                     if (month == -1) {
272                         try {
273                             month = Integer.parseInt(args[1].toString()) - 1;
274                         } catch (NumberFormatException JavaDoc nfExcptn) {
275                             throw getRuntime().newArgumentError("Argument out of range.");
276                         }
277                     }
278                 } else {
279                     month = (int)RubyNumeric.num2long(args[1]) - 1;
280                 }
281             }
282             if (0 > month || month > 11) {
283                 throw getRuntime().newArgumentError("Argument out of range.");
284             }
285         }
286
287         int[] int_args = { 1, 0, 0, 0, 0 };
288
289         for (int i = 0; len > i + 2; i++) {
290             if (!args[i + 2].isNil()) {
291                 if(!(args[i+2] instanceof RubyNumeric)) {
292                     args[i+2] = args[i+2].callMethod(tc,"to_i");
293                 }
294                 int_args[i] = (int)RubyNumeric.num2long(args[i + 2]);
295                 if (time_min[i] > int_args[i] || int_args[i] > time_max[i]) {
296                     throw getRuntime().newArgumentError("Argument out of range.");
297                 }
298             }
299         }
300         
301         if (year < 100) year += 2000;
302         
303         Calendar JavaDoc cal;
304         if (gmt) {
305             cal = Calendar.getInstance(TimeZone.getTimeZone(RubyTime.UTC));
306         } else {
307             cal = Calendar.getInstance(RubyTime.getLocalTimeZone(getRuntime()));
308         }
309         cal.set(year, month, int_args[0], int_args[1], int_args[2], int_args[3]);
310         cal.set(Calendar.MILLISECOND, int_args[4] / 1000);
311         if (cal.getTimeInMillis() / 1000 < -0x80000000) {
312             throw getRuntime().newArgumentError("time out of range");
313         }
314         RubyTime time = new RubyTime(getRuntime(), (RubyClass) this, cal);
315         time.setUSec(int_args[4] % 1000);
316
317         time.callInit(args, Block.NULL_BLOCK);
318
319         return time;
320     }
321 }
322
Popular Tags