Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com> Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de> Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr> Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se> Copyright (C) 2004 Joey Gibson <joey@joeygibson.com> Copyright (C) 2004 Charles O Nutter <headius@headius.com> Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de> Copyright (C) 2006 Thomas E Enebo <enebo@acm.org> Copyright (C) 2006 Ola Bini <ola.bini@ki.se> Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com> Copyright (C) 2009 Joseph LaFata <joe@quibb.org> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
  
  package org.jruby;
  
  import java.util.Date;
  import java.util.HashMap;
  import java.util.Locale;
  import java.util.Map;
  
  import static org.jruby.runtime.Visibility.PRIVATE;
  import static org.jruby.CompatVersion.*;
  
  import static org.jruby.javasupport.util.RuntimeHelpers.invokedynamic;
  import static org.jruby.runtime.invokedynamic.MethodNames.OP_CMP;

The Time class.

Author(s):
chadfowler, jpetersen
  
  @JRubyClass(name="Time", include="Comparable")
  public class RubyTime extends RubyObject {
      public static final String UTC = "UTC";
      private DateTime dt;
      private long nsec;
      
      private final static DateTimeFormatter ONE_DAY_CTIME_FORMATTER = DateTimeFormat.forPattern("EEE MMM  d HH:mm:ss yyyy").withLocale(.);
      private final static DateTimeFormatter TWO_DAY_CTIME_FORMATTER = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss yyyy").withLocale(.);
  
      private final static DateTimeFormatter TO_S_FORMATTER = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss Z yyyy").withLocale(.);
      private final static DateTimeFormatter TO_S_UTC_FORMATTER = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss 'UTC' yyyy").withLocale(.);
  
      private final static DateTimeFormatter TO_S_FORMATTER_19 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z").withLocale(.);
      private final static DateTimeFormatter TO_S_UTC_FORMATTER_19 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss 'UTC'").withLocale(.);
      // There are two different popular TZ formats: legacy (AST+3:00:00, GMT-3), and
      // newer one (US/Pacific, America/Los_Angeles). This pattern is to detect
      // the legacy TZ format in order to convert it to the newer format
      // understood by Java API.
      private static final Pattern TZ_PATTERN
              = Pattern.compile("(\\D+?)([\\+-]?)(\\d+)(:\\d+)?(:\\d+)?");
      
      private static final Pattern TIME_OFFSET_PATTERN
              = Pattern.compile("([\\+-])(\\d\\d):(\\d\\d)");
  
      private static final ByteList TZ_STRING = ByteList.create("TZ");
      
      /* JRUBY-3560
      * joda-time disallows use of three-letter time zone IDs.
      * Since MRI accepts these values, we need to translate them.
      */
     private static final Map<StringStringLONG_TZNAME = new HashMap<StringString>() {{
         put("MET""CET"); // JRUBY-2579
         put("ROC""Asia/Taipei"); // Republic of China
         put("WET""Europe/Lisbon"); // Western European Time
         
     }};
     
     /* Some TZ values need to be overriden for Time#zone
      */
     private static final Map<StringStringSHORT_STD_TZNAME = new HashMap<StringString>() {{
         put("Etc/UCT""UCT");
         put("MET""MET"); // needs to be overriden
         put("UCT","UCT");
     }};
 
     private static final Map<StringStringSHORT_DL_TZNAME = new HashMap<StringString>() {{
         put("Etc/UCT""UCT");
         put("MET""MEST"); // needs to be overriden
         put("UCT","UCT");
     }};
 
     @Override
     public int getNativeTypeIndex() {
         return .;
     }
     
     private static IRubyObject getEnvTimeZone(Ruby runtime) {
         RubyString tzVar = runtime.newString();
         RubyHash h = ((RubyHash)runtime.getObject().getConstant("ENV"));
         IRubyObject tz = h.op_aref(runtime.getCurrentContext(), tzVar);
         return tz;
     }
 
     public static DateTimeZone getLocalTimeZone(Ruby runtime) {
         IRubyObject tz = getEnvTimeZone(runtime);
 
         if (tz == null || ! (tz instanceof RubyString)) {
             return DateTimeZone.getDefault();
         } else {
             return getTimeZone(runtimetz.toString());
         }
     }
      
     public static DateTimeZone getTimeZone(Ruby runtimeString zone) {
         DateTimeZone cachedZone = runtime.getTimezoneCache().get(zone);
 
         if (cachedZone != nullreturn cachedZone;
 
         String originalZone = zone;
         TimeZone tz = TimeZone.getTimeZone(getEnvTimeZone(runtime).toString());
 
         // Value of "TZ" property is of a bit different format,
         // which confuses the Java's TimeZone.getTimeZone(id) method,
         // and so, we need to convert it.
 
         Matcher tzMatcher = .matcher(zone);
         if (tzMatcher.matches()) {                    
             String sign = tzMatcher.group(2);
             String hours = tzMatcher.group(3);
             String minutes = tzMatcher.group(4);
                 
             // GMT+00:00 --> Etc/GMT, see "MRI behavior"
             // comment below.
             if (("00".equals(hours) || "0".equals(hours)) &&
                     (minutes == null || ":00".equals(minutes) || ":0".equals(minutes))) {
                 zone = "Etc/GMT";
             } else {
                 // Invert the sign, since TZ format and Java format
                 // use opposite signs, sigh... Also, Java API requires
                 // the sign to be always present, be it "+" or "-".
                 sign = ("-".equals(sign)? "+" : "-");
 
                 // Always use "GMT" since that's required by Java API.
                 zone = "GMT" + sign + hours;
 
                 if (minutes != null) {
                     zone += minutes;
                 }
             }
             
             tz = TimeZone.getTimeZone(zone);
         } else {
             if (.containsKey(zone)) tz.setID(.get(zone.toUpperCase()));
         }
 
         // MRI behavior: With TZ equal to "GMT" or "UTC", Time.now
         // is *NOT* considered as a proper GMT/UTC time:
         //   ENV['TZ']="GMT"
         //   Time.now.gmt? ==> false
         //   ENV['TZ']="UTC"
         //   Time.now.utc? ==> false
         // Hence, we need to adjust for that.
         if ("GMT".equalsIgnoreCase(zone) || "UTC".equalsIgnoreCase(zone)) {
             zone = "Etc/" + zone;
             tz = TimeZone.getTimeZone(zone);
         }
 
         DateTimeZone dtz = DateTimeZone.forTimeZone(tz);
         runtime.getTimezoneCache().put(originalZonedtz);
         return dtz;
     }
     
     public RubyTime(Ruby runtimeRubyClass rubyClass) {
         super(runtimerubyClass);
     }
     
     public RubyTime(Ruby runtimeRubyClass rubyClassDateTime dt) {
         super(runtimerubyClass);
         this. = dt;
     }
 
     private static ObjectAllocator TIME_ALLOCATOR = new ObjectAllocator() {
         public IRubyObject allocate(Ruby runtimeRubyClass klass) {
             DateTimeZone dtz = getLocalTimeZone(runtime);
             DateTime dt = new DateTime(dtz);
             RubyTime rt =  new RubyTime(runtimeklassdt);
             rt.setNSec(0);
 
             return rt;
         }
     };
 
     public static RubyClass createTimeClass(Ruby runtime) {
         RubyClass timeClass = runtime.defineClass("Time"runtime.getObject(), );
 
         timeClass.index = .;
         timeClass.setReifiedClass(RubyTime.class);
         
         runtime.setTime(timeClass);
         
         timeClass.includeModule(runtime.getComparable());
         
         timeClass.defineAnnotatedMethods(RubyTime.class);
         
         return timeClass;
     }
     
     public void setNSec(long nsec) {
         this. = nsec;
     }
 
     public long getNSec() {
         return ;
     }
 
     public void setUSec(long usec) {
         this. = 1000 * usec;
     }
     
     public long getUSec() {
         return  / 1000;
     }
     
     public void updateCal(DateTime dt) {
         this. = dt;
     }
     
     protected long getTimeInMillis() {
         return .getMillis();
     }
     
     public static RubyTime newTime(Ruby runtimelong milliseconds) {
         return newTime(runtimenew DateTime(milliseconds));
     }
     
     public static RubyTime newTime(Ruby runtimeDateTime dt) {
         return new RubyTime(runtimeruntime.getTime(), dt);
     }
     
     public static RubyTime newTime(Ruby runtimeDateTime dtlong nsec) {
         RubyTime t = new RubyTime(runtimeruntime.getTime(), dt);
         t.setNSec(nsec);
         return t;
     }
     
     @Override
     public Class<?> getJavaClass() {
         return Date.class;
     }
 
     @JRubyMethod(name = "initialize_copy", required = 1)
     @Override
     public IRubyObject initialize_copy(IRubyObject original) {
         if (!(original instanceof RubyTime)) {
             throw getRuntime().newTypeError("Expecting an instance of class Time");
         }
         
         RubyTime originalTime = (RubyTimeoriginal;
         
         // We can just use dt, since it is immutable
          = originalTime.dt;
          = originalTime.nsec;
         
         return this;
     }
 
     @JRubyMethod(name = "succ")
     public RubyTime succ() {
         return newTime(getRuntime(),.plusSeconds(1));
     }
 
     @JRubyMethod(name = {"gmtime""utc"})
     public RubyTime gmtime() {
          = .withZone(.);
         return this;
     }
 
     @JRubyMethod(name = "localtime")
     public RubyTime localtime() {
          = .withZone(getLocalTimeZone(getRuntime()));
         return this;
     }
     
     @JRubyMethod(name = "localtime", optional = 1, compat = )
     public RubyTime localtime19(ThreadContext contextIRubyObject[] args) {
         if (args.length == 0) return localtime();
         String offset = args[0].asJavaString();
 
         Matcher offsetMatcher = .matcher(offset);
         if (! offsetMatcher.matches()) {
             throw context.runtime.newArgumentError("\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
         }
 
         String sign = offsetMatcher.group(1);
         String hours = offsetMatcher.group(2);
         String minutes = offsetMatcher.group(3);
         String zone;
 
         if ("00".equals(hours) && "00".equals(minutes)) {
             zone = "Etc/GMT";
         } else {
             // Java needs the sign inverted
             String sgn = "+".equals(sign) ? "-" : "+";
             zone = "GMT" + sgn + hours + minutes;
         }
 
         DateTimeZone dtz = getTimeZone(context.runtimezone);
         return newTime(context.runtime.withZone(dtz), );
     }
     
     @JRubyMethod(name = {"gmt?""utc?""gmtime?"})
     public RubyBoolean gmt() {
         return getRuntime().newBoolean(.getZone().getID().equals("UTC"));
     }
     
     @JRubyMethod(name = {"getgm""getutc"})
     public RubyTime getgm() {
         return newTime(getRuntime(), .withZone(.), );
     }
 
     @JRubyMethod(name = "getlocal")
     public RubyTime getlocal() {
         return newTime(getRuntime(), .withZone(getLocalTimeZone(getRuntime())), );
     }
 
     @JRubyMethod(name = "strftime", required = 1)
     public RubyString strftime(IRubyObject format) {
         final RubyDateFormat rubyDateFormat = getRuntime().getCurrentContext().getRubyDateFormat();
         rubyDateFormat.applyPattern(format.convertToString().getUnicodeValue());
         rubyDateFormat.setDateTime();
         rubyDateFormat.setNSec();
         String result = rubyDateFormat.format(null);
         return getRuntime().newString(result);
     }
 
     @JRubyMethod(name = "==", required = 1, compat= .)
     public IRubyObject op_equal(ThreadContext contextIRubyObject other) {
         if (other.isNil()) {
             return RubyBoolean.newBoolean(getRuntime(), false);
         } else if (other instanceof RubyTime) {
             return getRuntime().newBoolean(cmp((RubyTimeother) == 0);
         }
 
         return RubyComparable.op_equal(contextthisother);
     }
     
     @JRubyMethod(name = ">=", required = 1)
     public IRubyObject op_ge(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyTime) {
             return getRuntime().newBoolean(cmp((RubyTimeother) >= 0);
         }
         
         return RubyComparable.op_ge(contextthisother);
     }
     
     @JRubyMethod(name = ">", required = 1)
     public IRubyObject op_gt(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyTime) {
             return getRuntime().newBoolean(cmp((RubyTimeother) > 0);
         }
         
         return RubyComparable.op_gt(contextthisother);
     }
     
     @JRubyMethod(name = "<=", required = 1)
     public IRubyObject op_le(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyTime) {
             return getRuntime().newBoolean(cmp((RubyTimeother) <= 0);
         }
         
         return RubyComparable.op_le(contextthisother);
     }
     
     @JRubyMethod(name = "<", required = 1)
     public IRubyObject op_lt(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyTime) {
             return getRuntime().newBoolean(cmp((RubyTimeother) < 0);
         }
         
         return RubyComparable.op_lt(contextthisother);
     }
     
     private int cmp(RubyTime other) {
         Ruby runtime = getRuntime();
 
         long millis = getTimeInMillis();
 		long millis_other = other.getTimeInMillis();
         // ignore < usec on 1.8
         long nsec = runtime.is1_9() ? this. : (this. / 1000 * 1000);
         long nsec_other = runtime.is1_9() ? other.nsec : (other.nsec / 1000 * 1000);
 
 		if (millis > millis_other || (millis == millis_other && nsec > nsec_other)) {
 		    return 1;
 		} else if (millis < millis_other || (millis == millis_other && nsec < nsec_other)) {
 		    return -1;
 		}
 
         return 0;
     }
 
     @JRubyMethod(name = "+", required = 1, compat = .)
     public IRubyObject op_plus(IRubyObject other) {
         if (other instanceof RubyTime) {
             throw getRuntime().newTypeError("time + time ?");
         }
         long adjustment = Math.round(RubyNumeric.num2dbl(other) * 1000000);
 
         return opPlusMicros(adjustment);
     }
 
     @JRubyMethod(name = "+", required = 1, compat = .)
     public IRubyObject op_plus19(ThreadContext contextIRubyObject other) {
         checkOpCoercion(contextother);
         if (other instanceof RubyTime) {
             throw getRuntime().newTypeError("time + time ?");
         }
         other = other.callMethod(context"to_r");
 
         long adjustNanos = (long)(RubyNumeric.num2dbl(other) * 1000000000);
         return opPlusNanos(adjustNanos);
     }
 
     private IRubyObject opPlusMicros(long adjustMicros) {
         long adjustNanos = adjustMicros * 1000;
 
         long currentNanos = getTimeInMillis() * 1000000 + ;
 
         long newNanos = currentNanos += adjustNanos;
         long newMillisPart = newNanos / 1000000;
         long newNanosPart = newNanos % 1000000;
 
         RubyTime newTime = new RubyTime(getRuntime(), getMetaClass());
         newTime.dt = new DateTime(newMillisPart).withZone(.getZone());
         newTime.setNSec(newNanosPart);
 
         return newTime;
     }
 
     private IRubyObject opPlusNanos(long adjustNanos) {
         long currentNanos = getTimeInMillis() * 1000000 + ;
 
         long newNanos = currentNanos + adjustNanos;
         long newMillisPart = newNanos / 1000000;
         long newNanosPart = newNanos % 1000000;
 
         RubyTime newTime = new RubyTime(getRuntime(), getMetaClass());
         newTime.dt = new DateTime((long)newMillisPart).withZone(.getZone());
         newTime.setNSec(newNanosPart);
 
         return newTime;
     }
 
     private void checkOpCoercion(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyString) {
             throw context.runtime.newTypeError("no implicit conversion to rational from string");
         } else if (other.isNil()) {
             throw context.runtime.newTypeError("no implicit conversion to rational from nil");
         } else if (!other.respondsTo("to_r")){
             throw context.runtime.newTypeError("can't convert " + other.getMetaClass().getBaseName() + " into Rational");
         }
     }
 
     private IRubyObject opMinus(RubyTime other) {
         long time = getTimeInMillis() * 1000000 + getNSec();
 
         time -= other.getTimeInMillis() * 1000000 + other.getNSec();
         
         return RubyFloat.newFloat(getRuntime(), time / 1000000000.0); // float number of seconds
     }
 
     @JRubyMethod(name = "-", required = 1, compat = .)
     public IRubyObject op_minus(IRubyObject other) {
         if (other instanceof RubyTimereturn opMinus((RubyTimeother);
         return opMinusCommon(other);
     }
 
     @JRubyMethod(name = "-", required = 1, compat = .)
     public IRubyObject op_minus19(ThreadContext contextIRubyObject other) {
         checkOpCoercion(contextother);
         if (other instanceof RubyTimereturn opMinus((RubyTimeother);
         return opMinusCommon(other.callMethod(context"to_r"));
     }
 
     private IRubyObject opMinusCommon(IRubyObject other) {
         long time = getTimeInMillis();
         long adjustment = Math.round(RubyNumeric.num2dbl(other) * 1000000);
         long nano = (adjustment % 1000) * 1000;
         adjustment = adjustment / 1000;
 
         time -= adjustment;
 
         if (getNSec() < nano) {
             time--;
             nano = 1000000 - (nano - getNSec());
         } else {
             nano = getNSec() - nano;
         }
 
         RubyTime newTime = new RubyTime(getRuntime(), getMetaClass());
         newTime.dt = new DateTime(time).withZone(.getZone());
         newTime.setNSec(nano);
 
         return newTime;
     }
 
     @JRubyMethod(name = "===", required = 1)
     @Override
     public IRubyObject op_eqq(ThreadContext contextIRubyObject other) {
         return (RubyNumeric.fix2int(invokedynamic(contextthisother)) == 0) ? getRuntime().getTrue() : getRuntime().getFalse();
     }
 
     @JRubyMethod(name = "<=>", required = 1, compat = .)
     public IRubyObject op_cmp(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyTime) {
             return context.runtime.newFixnum(cmp((RubyTimeother));
         }
         return context.runtime.getNil();
     }
 
     @JRubyMethod(name = "<=>", required = 1, compat = .)
     public IRubyObject op_cmp19(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyTime) {
             return context.runtime.newFixnum(cmp((RubyTimeother));
         }
 
         IRubyObject tmp = invokedynamic(contextotherthis);
         if (tmp.isNil()) {
             return context.runtime.getNil();
         } else {
             int n = -RubyComparable.cmpint(contexttmpthisother);
             if (n == 0) return context.runtime.newFixnum(0);
             if (n > 0) return context.runtime.newFixnum(1);
             return context.runtime.newFixnum(-1);
         }
     }
 
     @JRubyMethod(name = "eql?", required = 1)
     @Override
     public IRubyObject eql_p(IRubyObject other) {
         if (other instanceof RubyTime) {
             RubyTime otherTime = (RubyTime)other
             return ( == otherTime.nsec && getTimeInMillis() == otherTime.getTimeInMillis()) ? getRuntime().getTrue() : getRuntime().getFalse();
         }
         return getRuntime().getFalse();
     }
 
     @JRubyMethod(name = {"asctime""ctime"})
     public RubyString asctime() {
         DateTimeFormatter simpleDateFormat;
 
         if (.getDayOfMonth() < 10) {
             simpleDateFormat = ;
         } else {
             simpleDateFormat = ;
         }
         String result = simpleDateFormat.print();
         return getRuntime().newString(result);
     }
 
     @JRubyMethod(name = {"to_s""inspect"}, compat = .)
     @Override
     public IRubyObject to_s() {
         return inspectCommon();
     }
 
     @JRubyMethod(name = {"to_s""inspect"}, compat = .)
     public IRubyObject to_s19() {
     }
 
     private IRubyObject inspectCommon(DateTimeFormatter formatterDateTimeFormatter utcFormatter) {
         DateTimeFormatter simpleDateFormat;
         if (.getZone() == .) {
             simpleDateFormat = utcFormatter;
         } else {
             simpleDateFormat = formatter;
         }
 
         String result = simpleDateFormat.print();
 
         return getRuntime().newString(result);
     }
 
     @JRubyMethod(name = "to_a")
     @Override
     public RubyArray to_a() {
         return getRuntime().newArrayNoCopy(new IRubyObject[] { sec(), min(), hour(), mday(), month(), 
                 year(), wday(), yday(), isdst(), zone() });
     }
 
     @JRubyMethod(name = "to_f")
     public RubyFloat to_f() {
         long millis = getTimeInMillis();
         long nanos = ;
         double secs = 0;
         if (millis != 0) secs += (millis / 1000.0);
         if (nanos != 0) secs += (nanos / 1000000000.0);
         return RubyFloat.newFloat(getRuntime(), secs);
     }
 
     @JRubyMethod(name = {"to_i""tv_sec"})
     public RubyInteger to_i() {
         return getRuntime().newFixnum(getTimeInMillis() / 1000);
     }
 
     @JRubyMethod(name = {"nsec""tv_nsec"}, compat = )
     public RubyInteger nsec() {
         return getRuntime().newFixnum((getTimeInMillis() % 1000) * 1000000 + );
     }
 
     @JRubyMethod(name = "to_r", compat = .)
     public IRubyObject to_r(ThreadContext context) {
         IRubyObject rational = to_f().to_r(context);
         if (rational instanceof RubyRational) {
             IRubyObject denominator = ((RubyRational)rational).denominator(context);
             if (RubyNumeric.num2long(denominator) == 1) {
                 return ((RubyRational)rational).numerator(context);
             }
         }
 
         return rational;
     }
 
     @JRubyMethod(name = {"usec""tv_usec"})
     public RubyInteger usec() {
         return getRuntime().newFixnum(.getMillisOfSecond() * 1000 + getUSec());
     }
 
     public void setMicroseconds(long mic) {
         long millis = getTimeInMillis() % 1000;
         long withoutMillis = getTimeInMillis() - millis;
         withoutMillis += (mic / 1000);
          = .withMillis(withoutMillis);
          = (mic % 1000) * 1000;
     }
     
     public long microseconds() {
     	return getTimeInMillis() % 1000 * 1000 + getUSec();
     }
 
     @JRubyMethod(name = "sec")
     public RubyInteger sec() {
         return getRuntime().newFixnum(.getSecondOfMinute());
     }
 
     @JRubyMethod(name = "min")
     public RubyInteger min() {
         return getRuntime().newFixnum(.getMinuteOfHour());
     }
 
     @JRubyMethod(name = "hour")
     public RubyInteger hour() {
         return getRuntime().newFixnum(.getHourOfDay());
     }
 
     @JRubyMethod(name = {"mday""day"})
     public RubyInteger mday() {
         return getRuntime().newFixnum(.getDayOfMonth());
     }
 
     @JRubyMethod(name = {"month""mon"})
     public RubyInteger month() {
         return getRuntime().newFixnum(.getMonthOfYear());
     }
 
     @JRubyMethod(name = "year")
     public RubyInteger year() {
         return getRuntime().newFixnum(.getYear());
     }
 
     @JRubyMethod(name = "wday")
     public RubyInteger wday() {
         return getRuntime().newFixnum((.getDayOfWeek()%7));
     }
 
     @JRubyMethod(name = "yday")
     public RubyInteger yday() {
         return getRuntime().newFixnum(.getDayOfYear());
     }
 
     @JRubyMethod(name = "subsec", compat = .)
     public IRubyObject subsec() {
         Ruby runtime = getRuntime();
         long nsec = .getMillisOfSecond() * 1000000 + this.;
 
         if (nsec % 1000000000 == 0) return RubyFixnum.zero(runtime);
 
         return runtime.newRationalReduced(
                 nsec, 1000000000);
     }
 
     @JRubyMethod(name = {"gmt_offset""gmtoff""utc_offset"})
     public RubyInteger gmt_offset() {
         int offset = .getZone().getOffset(.getMillis());
         
         return getRuntime().newFixnum((int)(offset/1000));
     }
 
     @JRubyMethod(name = {"isdst""dst?"})
     public RubyBoolean isdst() {
         return getRuntime().newBoolean(!.getZone().isStandardOffset(.getMillis()));
     }
 
     @JRubyMethod(name = "zone")
     public RubyString zone() {
         Ruby runtime = getRuntime();
         String envTZ = getEnvTimeZone(runtime).toString();
         // see declaration of SHORT_TZNAME
         if (.containsKey(envTZ) && ! .getZone().toTimeZone().inDaylightTime(.toDate())) {
             return runtime.newString(.get(envTZ));
         }
         
         if (.containsKey(envTZ) && .getZone().toTimeZone().inDaylightTime(.toDate())) {
             return runtime.newString(.get(envTZ));
         }
         
         String zone = .getZone().getShortName(.getMillis());
         
         Matcher offsetMatcher = .matcher(zone);
         
         if (offsetMatcher.matches()) {
             boolean minus_p = offsetMatcher.group(1).toString().equals("-");
             int hourOffset  = Integer.valueOf(offsetMatcher.group(2));
                         
             if (zone.equals("+00:00")) {
                 zone = "GMT";
             } else {
                 // try non-localized time zone name
                 zone = .getZone().getNameKey(.getMillis());
                 if (zone == null) {
                     char sign = minus_p ? '+' : '-';
                     zone = "GMT" + sign + hourOffset;
                 }
             }
         }
         
         return runtime.newString(zone);
     }
 
     public void setDateTime(DateTime dt) {
         this. = dt;
     }
 
     public DateTime getDateTime() {
         return this.;
     }
 
     public Date getJavaDate() {
         return this..toDate();
     }
 
     @JRubyMethod(name = "hash")
     @Override
     public RubyFixnum hash() {
     	// modified to match how hash is calculated in 1.8.2
         return getRuntime().newFixnum((int)(((.getMillis() / 1000) ^ microseconds()) << 1) >> 1);
     }    
 
     @JRubyMethod(name = "_dump", optional = 1)
     public RubyString dump(IRubyObject[] argsBlock unusedBlock) {
         RubyString str = (RubyStringmdump();
         str.syncVariables(this);
         return str;
     }    
 
     public RubyObject mdump() {
         Ruby runtime = getRuntime();
         RubyTime obj = this;
         DateTime dateTime = obj.dt.toDateTime(.);
         byte dumpValue[] = new byte[8];
         long nanos = this.;
         long usec = this. / 1000;
         long nsec = this. % 1000;
         
         int pe = 
             0x1                                 << 31 |
             ((obj.gmt().isTrue())? 0x1 : 0x0)   << 30 |
             (dateTime.getYear()-1900)           << 14 |
             (dateTime.getMonthOfYear()-1)       << 10 |
             dateTime.getDayOfMonth()            << 5  |
             dateTime.getHourOfDay();
         int se =
             dateTime.getMinuteOfHour()          << 26 |
             dateTime.getSecondOfMinute()        << 20 |
             (dateTime.getMillisOfSecond() * 1000 + (int)usec); // dump usec, not msec
 
         for(int i = 0; i < 4; i++) {
             dumpValue[i] = (byte)(pe & 0xFF);
             pe >>>= 8;
         }
         for(int i = 4; i < 8 ;i++) {
             dumpValue[i] = (byte)(se & 0xFF);
             se >>>= 8;
         }
 
         RubyString string = RubyString.newString(obj.getRuntime(), new ByteList(dumpValue));
 
         // 1.9 includes more nsecs
         if (runtime.is1_9()) {
             copyInstanceVariablesInto(string);
 
             // nanos in numerator/denominator form
             if (nsec != 0) {
                 string.setInternalVariable("nano_num"runtime.newFixnum(nsec));
                 string.setInternalVariable("nano_den"runtime.newFixnum(1));
             }
 
             // submicro for 1.9.1 compat
             byte[] submicro = new byte[2];
             int len = 2;
             submicro[1] = (byte)((nsec % 10) << 4);
             nsec /= 10;
             submicro[0] = (byte)(nsec % 10);
             nsec /= 10;
             submicro[0] |= (byte)((nsec % 10) << 4);
             if (submicro[1] == 0) len = 1;
             string.setInternalVariable("submicro", RubyString.newString(runtimesubmicro, 0, len));
 
             // time zone
             if (.getZone() != .) {
                 long offset = .getZone().getOffset(.getMillis());
                 string.setInternalVariable("offset"runtime.newFixnum(offset / 1000));
             }
         }
         return string;
     }
 
     @JRubyMethod(visibility = )
     public IRubyObject initialize(Block block) {
         return this;
     }
     
     @JRubyMethod(name = "round", optional = 1, compat = )
     public RubyTime round(ThreadContext contextIRubyObject[] args) {
         int ndigits = args.length == 0 ? 0 : RubyNumeric.num2int(args[0]);
         // There are only 1_000_000_000 nanoseconds in 1 second,
         // so there is no need to keep more than 9 digits
         if (ndigits > 9) {
             ndigits = 9;
         } else if (ndigits < 0) {
             throw context.getRuntime().newArgumentError("negative ndigits given");
         }
         
         RubyTime newTime = new RubyTime(getRuntime(), getMetaClass(), this.);
         long millis = newTime.dt.getMillis();
         double rounded = Math.round(millis * 1000000 / Math.pow(10, 9 - ndigits))
                 * Math.pow(10, 9 - ndigits);
         newTime.dt = newTime.dt.withMillis((longrounded / 1000000);
         
         return newTime;
     }
 
    /* Time class methods */
     
     public static IRubyObject s_new(IRubyObject recvIRubyObject[] argsBlock block) {
         Ruby runtime = recv.getRuntime();
         RubyTime time = new RubyTime(runtime, (RubyClassrecvnew DateTime(getLocalTimeZone(runtime)));
         time.callInit(args,block);
         return time;
     }

    
 
     @Deprecated
     public static IRubyObject newInstance(ThreadContext contextIRubyObject recvIRubyObject[] argsBlock block) {
         return newInstance(contextrecv);
     }
 
     @JRubyMethod(name = "times", meta = true, compat = .)
     public static IRubyObject times(ThreadContext contextIRubyObject recv) {
         context.runtime.getWarnings().warn("obsolete method Time::times; use Process::times");
         return RubyProcess.times(contextrecv.);
     }
 
     @JRubyMethod(name = "now", meta = true)
     public static IRubyObject newInstance(ThreadContext contextIRubyObject recv) {
         IRubyObject obj = ((RubyClassrecv).allocate();
         obj.getMetaClass().getBaseCallSite(.).call(contextrecvobj);
         return obj;
     }
 
     @JRubyMethod(name = "at",  meta = true)
     public static IRubyObject at(ThreadContext contextIRubyObject recvIRubyObject arg) {
         Ruby runtime = context.runtime;
         final RubyTime time;
 
         if (arg instanceof RubyTime) {
             RubyTime other = (RubyTimearg;
             time = new RubyTime(runtime, (RubyClassrecvother.dt);
             time.setNSec(other.getNSec());
         } else {
             time = new RubyTime(runtime, (RubyClassrecv,
                     new DateTime(0L, getLocalTimeZone(runtime)));
 
             long seconds = RubyNumeric.num2long(arg);
             long millisecs = 0;
             long nanosecs = 0;
 
             // In the case of two arguments, MRI will discard the portion of
             // the first argument after a decimal point (i.e., "floor").
             // However in the case of a single argument, any portion after
             // the decimal point is honored.
             if (arg instanceof RubyFloat || arg instanceof RubyRational) {
                 double dbl = RubyNumeric.num2dbl(arg);
                 long nano;
 
                 if (runtime.is1_9()) {
                     nano = Math.round((dbl - seconds) * 1000000000);
                 } else {
                     long micro = Math.round((dbl - seconds) * 1000000);
                     nano = micro * 1000;
                 }
 
                 if (dbl < 0 && nano != 0) {
                     nano += 1000000000;
                 }
                 millisecs = nano / 1000000;
                 nanosecs = nano % 1000000;
             }
             time.setNSec(nanosecs);
             time.dt = time.dt.withMillis(seconds * 1000 + millisecs);
         }
 
         time.getMetaClass().getBaseCallSite(.).call(contextrecvtime);
 
         return time;
     }
 
     @JRubyMethod(name = "at", meta = true)
     public static IRubyObject at(ThreadContext contextIRubyObject recvIRubyObject arg1IRubyObject arg2) {
         Ruby runtime = context.runtime;
 
         RubyTime time = new RubyTime(runtime, (RubyClassrecv,
                 new DateTime(0L, getLocalTimeZone(runtime)));
 
             long seconds = RubyNumeric.num2long(arg1);
             long millisecs = 0;
             long nanosecs = 0;
 
             if (arg2 instanceof RubyFloat || arg2 instanceof RubyRational) {
                 double micros = RubyNumeric.num2dbl(arg2);
                 double nanos = micros * 1000;
                 millisecs = (long)(nanos / 1000000);
                 nanosecs = (long)(nanos % 1000000);
             } else {
                 long micros = RubyNumeric.num2long(arg2);
                 long nanos = micros * 1000;
                 millisecs = nanos / 1000000;
                 nanosecs = nanos % 1000000;
             }
 
             time.setNSec(nanosecs);
             time.dt = time.dt.withMillis(seconds * 1000 + millisecs);
 
             time.getMetaClass().getBaseCallSite(.).call(contextrecvtime);
 
         return time;
     }
 
     @JRubyMethod(name = {"local""mktime"}, required = 1, optional = 9, meta = true)
     public static RubyTime new_local(IRubyObject recvIRubyObject[] args) {
         return createTime(recvargsfalse);
     }
 
     @JRubyMethod(name = "new", optional = 7, meta = true, compat = )
     public static IRubyObject new19(ThreadContext contextIRubyObject recvIRubyObject[] args) {
        if (args.length == 0) {
            return newInstance(contextrecv);
        }
        if (args.length == 7) {
          Ruby runtime = recv.getRuntime();
          // Convert the 7-argument form of Time.new into the 10-argument form of Time.local:
          args = new IRubyObject[] { args[5],          // seconds
                                     args[4],          // minutes
                                     args[3],          // hours
                                     args[2],          // day
                                     args[1],          // month
                                     args[0],          // year
                                     runtime.getNil(), // weekday
                                     runtime.getNil(), // day of year
                                     runtime.getNil(), // is DST?
                                     args[6] };        // UTC offset
        }
        return createTime(recvargsfalse);
    }
    @JRubyMethod(name = {"utc""gm"}, required = 1, optional = 9, meta = true)
    public static RubyTime new_utc(IRubyObject recvIRubyObject[] args) {