private static RubyTime createTime(IRubyObject recv, IRubyObject[] args, boolean gmt) {
Ruby runtime = recv.getRuntime();
int len = ARG_SIZE;
Boolean isDst = null;
DateTimeZone dtz;
if (gmt) {
dtz = DateTimeZone.UTC;
} else if (args.length == 10 && args[9] instanceof RubyString) {
dtz = getTimeZone(runtime, ((RubyString) args[9]).toString());
} else {
dtz = getLocalTimeZone(runtime);
}
if (args.length == 10) {
if (args[8] instanceof RubyBoolean) {
isDst = ((RubyBoolean) args[8]).isTrue();
}
args = new IRubyObject[] { args[5], args[4], args[3], args[2], args[1], args[0], runtime.getNil() };
} else {
// MRI accepts additional wday argument which appears to be ignored.
len = args.length;
if (len < ARG_SIZE) {
IRubyObject[] newArgs = new IRubyObject[ARG_SIZE];
System.arraycopy(args, 0, newArgs, 0, args.length);
for (int i = len; i < ARG_SIZE; i++) {
newArgs[i] = runtime.getNil();
}
args = newArgs;
len = ARG_SIZE;
}
}
if (args[0] instanceof RubyString) {
args[0] = RubyNumeric.str2inum(runtime, (RubyString) args[0], 10, false);
}
int year = (int) RubyNumeric.num2long(args[0]);
int month = 1;
if (len > 1) {
if (!args[1].isNil()) {
IRubyObject tmp = args[1].checkStringType();
if (!tmp.isNil()) {
String monthString = tmp.toString().toLowerCase();
Integer monthInt = MONTHS_MAP.get(monthString);
if (monthInt != null) {
month = monthInt;
} else {
try {
month = Integer.parseInt(monthString);
} catch (NumberFormatException nfExcptn) {
throw runtime.newArgumentError("Argument out of range.");
}
}
} else {
month = (int) RubyNumeric.num2long(args[1]);
}
}
if (1 > month || month > 12) {
throw runtime.newArgumentError("Argument out of range: for month: " + month);
}
}
int[] int_args = { 1, 0, 0, 0, 0, 0 };
for (int i = 0; int_args.length >= i + 2; i++) {
if (!args[i + 2].isNil()) {
if (!(args[i + 2] instanceof RubyNumeric)) {
args[i + 2] = args[i + 2].callMethod(
runtime.getCurrentContext(), "to_i");
}
long value = RubyNumeric.num2long(args[i + 2]);
if (time_min[i] > value || value > time_max[i]) {
throw runtime.newArgumentError("argument out of range.");
}
int_args[i] = (int) value;
}
}
if (!runtime.is1_9()) {
if (0 <= year && year < 39) {
year += 2000;
} else if (69 <= year && year < 139) {
year += 1900;
}
}
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);
dt = dt.plusMonths(month - 1)
.plusDays(int_args[0] - 1)
.plusHours(int_args[1])
.plusMinutes(int_args[2])
.plusSeconds(int_args[3]);
// 1.9 will observe fractional seconds *if* not given usec
if (runtime.is1_9() && !args[5].isNil()
&& args[6].isNil()) {
double millis = RubyFloat.num2dbl(args[5]);
int int_millis = (int) (millis * 1000) % 1000;
dt = dt.plusMillis(int_millis);
}
dt = dt.withZoneRetainFields(dtz);
// we might need to perform a DST correction
if (isDst != null) {
// the instant at which we will ask dtz what the difference between DST and
// standard time is
long offsetCalculationInstant = dt.getMillis();
// if we might be moving this time from !DST -> DST, the offset is assumed
// to be the same as it was just before we last moved from DST -> !DST
if (dtz.isStandardOffset(dt.getMillis())) {
offsetCalculationInstant = dtz.previousTransition(offsetCalculationInstant);
}
int offset = dtz.getStandardOffset(offsetCalculationInstant)
- dtz.getOffset(offsetCalculationInstant);
if (!isDst && !dtz.isStandardOffset(dt.getMillis())) {
dt = dt.minusMillis(offset);
}
if (isDst && dtz.isStandardOffset(dt.getMillis())) {
dt = dt.plusMillis(offset);
}
}
} catch (org.joda.time.IllegalFieldValueException e) {
throw runtime.newArgumentError("time out of range");