Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: EPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Eclipse 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/epl-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 EPL, 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 EPL, the GPL or the LGPL. END LICENSE BLOCK ***
  
  package org.jruby;
  
  import java.util.Date;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  
  import static org.jruby.runtime.Visibility.PRIVATE;
  
  import static org.jruby.CompatVersion.*;
  
  import static org.jruby.runtime.Helpers.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");
     
     private boolean isTzRelative = false// true if and only if #new is called with a numeric offset (e.g., "+03:00")
     
     /* 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 = Helpers.map(
         "MET""CET"// JRUBY-2759
         "ROC""Asia/Taipei"// Republic of China
         "WET""Europe/Lisbon" // Western European Time
     );
     
     /* github-215
      * Some non-JVM timezone names are recognized by MRI.
      * This map translate those to JVM-friendly names.
      */
     private static final Map<StringStringNON_JVM_TZNAME = Helpers.map(
         "EDT""EST",
         "CDT""CST",
         "MDT""MST",
         "PDT""PST"
     );
     
     /* Some TZ values need to be overriden for Time#zone
      */
     private static final Map<StringStringSHORT_STD_TZNAME = Helpers.map(
         "Etc/UCT""UCT",
         "MET""MET"// needs to be overriden
         "UCT""UCT"
     );
 
     private static final Map<StringStringSHORT_DL_TZNAME = Helpers.map(
         "Etc/UCT""UCT",
         "MET""MEST"// needs to be overriden
         "UCT""UCT"
     );
     
     private void setIsTzRelative(boolean tzRelative) {
          = tzRelative;
     }
 
     @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 runtimelong seconds) {
         if (seconds >= 60*60*24 || seconds <= -60*60*24) {
             throw runtime.newArgumentError("utc_offset out of range");
         }
         
         // append "s" to the offset when looking up the cache
         String zone = seconds + "s";
         DateTimeZone cachedZone = runtime.getTimezoneCache().get(zone);
 
         if (cachedZone != nullreturn cachedZone;
         DateTimeZone dtz = DateTimeZone.forOffsetMillis((int) (seconds * 1000));
         runtime.getTimezoneCache().put(zonedtz);
         return dtz;
     }
 
     public static DateTimeZone getTimeZone(Ruby runtimeString zone) {
         DateTimeZone cachedZone = runtime.getTimezoneCache().get(zone);
 
         if (cachedZone != nullreturn cachedZone;
 
         String originalZone = zone;
         if (.containsKey(zone.toUpperCase())) {
             zone = .get(zone.toUpperCase());
         }
         TimeZone tz = TimeZone.getTimeZone(zone);
 
         // 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);
             
             if (Integer.parseInt(hours) > 23 ||
                     (minutes != null && Integer.parseInt(minutes) > 59)) {
                 throw runtime.newArgumentError("utc_offset out of range");
             }
             
             // 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() {
         @Override
         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", compat = )
     public RubyTime getlocal() {
         return newTime(getRuntime(), .withZone(getLocalTimeZone(getRuntime())), );
     }
 
     @JRubyMethod(name = "getlocal", compat = , optional = 1)
     public RubyTime getlocal19(ThreadContext contextIRubyObject[] args) {
         if (args.length == 0) {
             return newTime(getRuntime(), .withZone(getLocalTimeZone(getRuntime())), );
         } else {
             Matcher tzMatcher = .matcher(args[0].toString());
             int hoursminutesmillis = 0;
             if (tzMatcher.matches()) {
                 hours = Integer.parseInt(tzMatcher.group(2));
                 minutes = Integer.parseInt(tzMatcher.group(3));
                 millis = (hours * 60 + minutes) * 60 * 1000;
                 if (tzMatcher.group(1).equals("-"))
                     millis = -millis;
             } else {
                 throw getRuntime().newArgumentError("\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
             }
             return newTime(getRuntime(), .withZone(DateTimeZone.forOffsetMillis(millis)), );
         }
     }
 
     @JRubyMethod(name = "strftime", required = 1)
     public RubyString strftime(IRubyObject format) {
         return rdf.compileAndFormat(format.convertToString(), falsenull);
     }
 
     @JRubyMethod(name = "==", required = 1, compat= .)
     @Override
     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_equal19(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 nanosec = 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 && nanosec > nsec_other)) {
 		    return 1;
 		} else if (millis < millis_other || (millis == millis_other && nanosec < 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 currentMillis = getTimeInMillis();
         
         long adjustMillis = adjustMicros/1000;
         long adjustNanosLeft = adjustMicros - (adjustMillis*1000);
         
         long newMillisPart = currentMillis + adjustMillis;
         long newNanosPart =  + adjustNanosLeft;
 
         RubyTime newTime = new RubyTime(getRuntime(), getMetaClass());
         newTime.dt = new DateTime(newMillisPart).withZone(.getZone());
         newTime.setNSec(newNanosPart);
 
         return newTime;
     }
 
     private IRubyObject opPlusNanos(long adjustNanos) {
         long currentMillis = getTimeInMillis();
         
         long adjustMillis = adjustNanos/1000000;
         long adjustNanosLeft = adjustNanos - (adjustMillis*1000000);
         
         long newMillisPart = currentMillis + adjustMillis;
         long newNanosPart =  + adjustNanosLeft;
 
         if (newNanosPart >= 1000000) {
             newNanosPart -= 1000000;
             newMillisPart++;
         }
 
         RubyTime newTime = new RubyTime(getRuntime(), getMetaClass());
         newTime.dt = new DateTime(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 timeInMillis = (getTimeInMillis() - other.getTimeInMillis());
         double timeInSeconds = timeInMillis/1000.0 + (getNSec() - other.getNSec())/1000000000.0;
         
         return RubyFloat.newFloat(getRuntime(), timeInSeconds); // 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 adjustmentInNanos = (long)(RubyNumeric.num2dbl(other)*1000000000);
         long adjustmentInMillis = adjustmentInNanos/1000000;
         long adjustmentInNanosLeft = adjustmentInNanos%1000000;
         
         long time = getTimeInMillis() - adjustmentInMillis;
         
         long nano;
         if ( < adjustmentInNanosLeft) {
             time--;
             nano = 1000000 - (adjustmentInNanosLeft - );
         } else {
             nano =  - adjustmentInNanosLeft;
         }
 
         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) {
         if (other instanceof RubyTime) {
             return context.runtime.newBoolean(RubyNumeric.fix2int(invokedynamic(contextthisother)) == 0);
         }
 
         return context.getRuntime().getFalse();
     }
 
     @JRubyMethod(name = "<=>", required = 1, compat = .)
     @Override
     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();
 
         if () {
             // display format needs to invert the UTC offset if this object was
             // created with a specific offset in the 7-arg form of #new
             DateTimeZone dtz = .getZone();
             int offset = (-1) * dtz.toTimeZone().getOffset(.getMillis());
             DateTimeZone invertedDTZ = DateTimeZone.forOffsetMillis(offset);
             DateTime invertedDT = .withZone(invertedDTZ);
             result = simpleDateFormat.print(invertedDT);
         }
 
         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 nanosec = .getMillisOfSecond() * 1000000 + this.;
 
         if (nanosec % 1000000000 == 0) return RubyFixnum.zero(runtime);
 
         return runtime.newRationalReduced(
                 nanosec, 1000000000);
     }
 
     @JRubyMethod(name = {"gmt_offset""gmtoff""utc_offset"})
     public RubyInteger gmt_offset() {
         int offset = .getZone().getOffset(.getMillis());
         if (offset = -offset;
         
         return getRuntime().newFixnum((int)(offset/1000));
     }
 
     @JRubyMethod(name = {"isdst""dst?"})
     public RubyBoolean isdst() {
         return getRuntime().newBoolean(!.getZone().isStandardOffset(.getMillis()));
     }
 
     @JRubyMethod(name = "zone")
     public IRubyObject zone() {
         Ruby runtime = getRuntime();
         if (return runtime.getNil();
         
         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 nanosec = 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 (nanosec != 0) {
                 string.setInternalVariable("nano_num"runtime.newFixnum(nanosec));
                 string.setInternalVariable("nano_den"runtime.newFixnum(1));
             }
 
             // submicro for 1.9.1 compat
             byte[] submicro = new byte[2];
             int len = 2;
             submicro[1] = (byte)((nanosec % 10) << 4);
             nanosec /= 10;
             submicro[0] = (byte)(nanosec % 10);
             nanosec /= 10;
             submicro[0] |= (byte)((nanosec % 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");
         }
 
         int nsec = this..getMillisOfSecond() * 1000000 + (int) (this.);
         int pow = (int) Math.pow(10, 9 - ndigits);
         int rounded = ((nsec + pow/2) / pow) * pow;
         DateTime dt = this..withMillisOfSecond(0).plusMillis(rounded / 1000000);
         return newTime(context.runtimedtrounded % 1000000);
     }
 
    /* 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,