1 38 package org.jruby.runtime.builtin.meta; 39 40 import java.util.Calendar ; 41 import java.util.Date ; 42 import java.util.GregorianCalendar ; 43 import java.util.TimeZone ; 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 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 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 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 cal = new GregorianCalendar (); 154 cal.setTime(new Date ()); 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 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 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 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 [] 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 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 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 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 |