Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1ea71f454d53
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2419fa0ada33
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Feb 6, 2018

  1. Copy the full SHA
    0f887c9 View commit details

Commits on Feb 7, 2018

  1. Copy the full SHA
    2419fa0 View commit details
Showing with 81 additions and 73 deletions.
  1. +77 −73 core/src/main/java/org/jruby/RubyTime.java
  2. +4 −0 core/src/main/java/org/jruby/runtime/JavaSites.java
150 changes: 77 additions & 73 deletions core/src/main/java/org/jruby/RubyTime.java
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@
import jnr.posix.POSIX;
import jnr.posix.Timeval;
import org.jcodings.specific.USASCIIEncoding;
import org.joda.time.Chronology;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.IllegalFieldValueException;
@@ -146,7 +147,7 @@ public ClassIndex getNativeClassIndex() {
}

private static IRubyObject getEnvTimeZone(Ruby runtime) {
RubyString tzVar = (RubyString)runtime.getTime().getInternalVariable("tz_string");
RubyString tzVar = (RubyString) runtime.getTime().getInternalVariable("tz_string");
if (tzVar == null) {
tzVar = runtime.newString(TZ_STRING);
tzVar.setFrozen(true);
@@ -160,20 +161,17 @@ public static DateTimeZone getLocalTimeZone(Ruby runtime) {

if (tz == null || ! (tz instanceof RubyString)) {
return DateTimeZone.getDefault();
} else {
return getTimeZoneFromTZString(runtime, tz.toString());
}
return getTimeZoneFromTZString(runtime, tz.toString());
}

public static DateTimeZone getTimeZoneFromTZString(Ruby runtime, String zone) {
DateTimeZone cachedZone = runtime.getTimezoneCache().get(zone);
if (cachedZone != null) {
return cachedZone;
} else {
DateTimeZone dtz = parseTZString(runtime, zone);
runtime.getTimezoneCache().put(zone, dtz);
return dtz;
}
if (cachedZone != null) return cachedZone;

DateTimeZone dtz = parseTZString(runtime, zone);
runtime.getTimezoneCache().put(zone, dtz);
return dtz;
}

private static DateTimeZone parseTZString(Ruby runtime, String zone) {
@@ -1116,8 +1114,8 @@ public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, I
}

@JRubyMethod(name = "now", meta = true)
public static IRubyObject newInstance(ThreadContext context, IRubyObject recv) {
IRubyObject obj = ((RubyClass) recv).allocate();
public static RubyTime newInstance(ThreadContext context, IRubyObject recv) {
RubyTime obj = (RubyTime) ((RubyClass) recv).allocate();
obj.getMetaClass().getBaseCallSite(RubyClass.CS_IDX_INITIALIZE).call(context, recv, obj);
return obj;
}
@@ -1178,16 +1176,10 @@ public static IRubyObject at(ThreadContext context, IRubyObject recv, IRubyObjec
}

try {
time = new RubyTime(runtime, (RubyClass) recv,
new DateTime(millisecs, getLocalTimeZone(runtime)));
}
// joda-time 2.5 can throw this exception - seen locally
catch(ArithmeticException e1) {
throw runtime.newRangeError(e1.getMessage());
time = new RubyTime(runtime, (RubyClass) recv, new DateTime(millisecs, getLocalTimeZone(runtime)));
}
// joda-time 2.5 can throw this exception - seen on travis
catch(IllegalFieldValueException e2) {
throw runtime.newRangeError(e2.getMessage());
catch (ArithmeticException|IllegalFieldValueException ex) {
throw runtime.newRangeError(ex.getMessage());
}

time.setNSec(nanosecs);
@@ -1244,51 +1236,60 @@ public static RubyTime local(ThreadContext context, IRubyObject recv, IRubyObjec
return createTime(context, (RubyClass) recv, args, false, false);
}

@Deprecated
public static RubyTime new_local(IRubyObject recv, IRubyObject[] args) {
return createTime(recv.getRuntime().getCurrentContext(), (RubyClass) recv, args, false, false);
}

@JRubyMethod(name = "new", optional = 7, meta = true)
public static IRubyObject new19(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
public static RubyTime newInstance(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
if (args.length == 0) return newInstance(context, recv);

if (args.length == 7) {
Ruby runtime = context.runtime;

// 7th argument can be the symbol :dst instead of an offset, so needs to be special cased
final RubySymbol dstSymbol = RubySymbol.newSymbol(runtime, "dst");
boolean receivedDstSymbolAsArgument = (args[6].op_equal(context, dstSymbol)).isTrue();

final RubyBoolean isDst = RubyBoolean.newBoolean(runtime, receivedDstSymbolAsArgument);

// 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
isDst, // is DST?
args[6] }; // UTC offset
Ruby runtime = context.runtime;

// 7th argument can be the symbol :dst instead of an offset, so needs to be special cased
boolean dst = (args[6] instanceof RubySymbol) && ((RubySymbol) args[6]).asJavaString().equals("dst");

// 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
context.nil, // weekday
context.nil, // day of year
RubyBoolean.newBoolean(runtime, dst), // is DST?
args[6] }; // UTC offset
}
return createTime(context, (RubyClass) recv, args, false, true);
}

@Deprecated
public static IRubyObject new19(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return newInstance(context, recv, args);
}

@JRubyMethod(name = {"utc", "gm"}, required = 1, optional = 9, meta = true)
public static RubyTime utc(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return createTime(context, (RubyClass) recv, args, true, false);
}

@Deprecated
public static RubyTime new_utc(IRubyObject recv, IRubyObject[] args) {
return createTime(recv.getRuntime().getCurrentContext(), (RubyClass) recv, args, true, false);
}

@JRubyMethod(name = "_load", meta = true)
@Deprecated
public static RubyTime load(IRubyObject recv, IRubyObject from, Block block) {
return s_mload(recv, (RubyTime)(((RubyClass)recv).allocate()), from);
return s_mload(recv.getRuntime().getCurrentContext(), (RubyTime) ((RubyClass) recv).allocate(), from);
}

@JRubyMethod(name = "_load", meta = true)
public static RubyTime load(ThreadContext context, IRubyObject recv, IRubyObject from) {
return s_mload(context, (RubyTime) ((RubyClass) recv).allocate(), from);
}

@Override
@@ -1347,15 +1348,15 @@ else if ( sec.respondsTo("divmod") ) {
return seconds;
}

protected static RubyTime s_mload(IRubyObject recv, RubyTime time, IRubyObject from) {
Ruby runtime = recv.getRuntime();
private static final DateTime TIME0 = new DateTime(0, DateTimeZone.UTC);

DateTime dt = new DateTime(DateTimeZone.UTC);
private static RubyTime s_mload(ThreadContext context, final RubyTime time, IRubyObject from) {
DateTime dt = TIME0;

byte[] fromAsBytes;
fromAsBytes = from.convertToString().getBytes();
if(fromAsBytes.length != 8) {
throw runtime.newTypeError("marshaled time format differ");
if (fromAsBytes.length != 8) {
throw context.runtime.newTypeError("marshaled time format differ");
}
int p=0;
int s=0;
@@ -1400,27 +1401,27 @@ protected static RubyTime s_mload(IRubyObject recv, RubyTime time, IRubyObject f

int offset = 0;
if (offsetVar != null && offsetVar.respondsTo("to_int")) {
final IRubyObject $ex = runtime.getCurrentContext().getErrorInfo();
final IRubyObject $ex = context.getErrorInfo();
try {
offset = offsetVar.convertToInteger().getIntValue() * 1000;
}
catch (RaiseException typeError) {
runtime.getCurrentContext().setErrorInfo($ex); // restore $!
context.setErrorInfo($ex); // restore $!
}
}

String zone = "";
if (zoneVar != null && zoneVar.respondsTo("to_str")) {
final IRubyObject $ex = runtime.getCurrentContext().getErrorInfo();
final IRubyObject $ex = context.getErrorInfo();
try {
zone = zoneVar.convertToString().toString();
}
catch (RaiseException typeError) {
runtime.getCurrentContext().setErrorInfo($ex); // restore $!
context.setErrorInfo($ex); // restore $!
}
}

time.dt = dt.withZone(getTimeZoneWithOffset(runtime, zone, offset));
time.dt = dt.withZone(getTimeZoneWithOffset(context.runtime, zone, offset));
return time;
}

@@ -1443,8 +1444,8 @@ private static RubyTime createTime(ThreadContext context, RubyClass klass, IRuby
} else {
dtz = getTimeZoneFromString(runtime, args[9].toString());
}
} else if (args.length == 10 && args[9].respondsTo("to_int")) {
IRubyObject offsetInt = args[9].callMethod(context, "to_int");
} else if (args.length == 10 && sites(context).respond_to_to_int.respondsTo(context, args[9], args[9])) {
IRubyObject offsetInt = sites(context).to_int.call(context, args[9], args[9]);
dtz = getTimeZone(runtime, ((RubyNumeric) offsetInt).getLongValue());
} else {
dtz = getLocalTimeZone(runtime);
@@ -1475,10 +1476,10 @@ private static RubyTime createTime(ThreadContext context, RubyClass klass, IRuby
int month = 1;

if (len > 1) {
if (!args[1].isNil()) {
if (args[1] != context.nil) {
month = parseMonth(context, args[1]);
}
if (1 > month || month > 12) {
if (month < 1 || month > 12) {
throw runtime.newArgumentError("Argument out of range: for month: " + month);
}
}
@@ -1503,24 +1504,25 @@ private static RubyTime createTime(ThreadContext context, RubyClass klass, IRuby
}

DateTime dt;
// set up with min values and then add to allow rolling over
try {
dt = new DateTime(year, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC);
try { // set up with min values and then add to allow rolling over
dt = new DateTime(year, month, 1, 0, 0, 0, 0, DateTimeZone.UTC);

dt = dt.plusMonths(month - 1)
.plusDays(i_args0 - 1)
.plusHours(i_args1)
.plusMinutes(i_args2)
.plusSeconds(i_args3);
final Chronology chrono = dt.getChronology();
long instant = dt.getMillis();
instant = chrono.days().add(instant, i_args0 - 1);
if (i_args1 != 0) instant = chrono.hours().add(instant, i_args1);
if (i_args2 != 0) instant = chrono.minutes().add(instant, i_args2);
if (i_args3 != 0) instant = chrono.seconds().add(instant, i_args3);

// 1.9 will observe fractional seconds *if* not given usec
if (!args[5].isNil() && args[6].isNil()) {
if (args[5] != context.nil && args[6] == context.nil) {
double secs = RubyFloat.num2dbl(args[5]);
int int_millis = (int) (secs * 1000) % 1000;
dt = dt.plusMillis(int_millis);
instant = chrono.millis().add(instant, int_millis);
nanos = ((long) (secs * 1000000000) % 1000000);
}

dt = dt.withMillis(instant);
dt = dt.withZoneRetainFields(dtz);

// If we're at a DST boundary, we need to choose the correct side of the boundary
@@ -1534,13 +1536,14 @@ private static RubyTime createTime(ThreadContext context, RubyClass klass, IRuby
// If the time is during DST, we need to pick the time with the highest offset
dt = offsetBeforeBoundary > offsetAfterBoundary ? beforeDstBoundary : afterDstBoundary;
}
} catch (org.joda.time.IllegalFieldValueException e) {
}
catch (org.joda.time.IllegalFieldValueException e) {
throw runtime.newArgumentError("time out of range");
}

RubyTime time = new RubyTime(runtime, klass, dt);
// Ignores usec if 8 args (for compatibility with parsedate) or if not supplied.
if (args.length != 8 && !args[6].isNil()) {
// Ignores usec if 8 args (for compatibility with parse-date) or if not supplied.
if (args.length != 8 && args[6] != context.nil) {
boolean fractionalUSecGiven = args[6] instanceof RubyFloat || args[6] instanceof RubyRational;

if (fractionalUSecGiven) {
@@ -1580,10 +1583,11 @@ private static int argToInt(final ThreadContext context, IRubyObject[] args, fin
IRubyObject arg = args[i];
if (arg != context.nil) {
if (!(arg instanceof RubyNumeric)) {
if (arg.respondsTo("to_int")) {
arg = args[i] = arg.callMethod(context, "to_int");
final TimeSites sites = sites(context);
if (sites.respond_to_to_int.respondsTo(context, arg, arg)) {
arg = args[i] = sites.to_int.call(context, arg, arg);
} else {
arg = args[i] = arg.callMethod(context, "to_i"); // TODO setting args[i] necessary?
arg = args[i] = sites.to_i.call(context, arg, arg);
}
}
return RubyNumeric.num2int(arg);
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/runtime/JavaSites.java
Original file line number Diff line number Diff line change
@@ -287,6 +287,10 @@ public IRubyObject call(ThreadContext context, IRubyObject recv, IRubyObject oth
return cmp.call(context, other, other, recv);
}
};

public final RespondToCallSite respond_to_to_int = new RespondToCallSite("to_int");
public final CachingCallSite to_int = new FunctionalCachingCallSite("to_int");
public final CachingCallSite to_i = new FunctionalCachingCallSite("to_i");
}

public static class EnumerableSites {