Skip to content

Commit

Permalink
[fix] cast nsec nanos to long to avoid "overflow" with double value
Browse files Browse the repository at this point in the history
fixes #4989 ... follow-up on #4866 (4be8d66)
kares committed Mar 27, 2018

Verified

This commit was signed with the committer’s verified signature.
headius Charles Oliver Nutter
1 parent 1718c4a commit 682626e
Showing 2 changed files with 54 additions and 18 deletions.
30 changes: 12 additions & 18 deletions core/src/main/java/org/jruby/RubyTime.java
Original file line number Diff line number Diff line change
@@ -1549,22 +1549,17 @@ private static RubyTime createTime(ThreadContext context, RubyClass klass, IRuby
}

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()) {
boolean fractionalUSecGiven = args[6] instanceof RubyFloat || args[6] instanceof RubyRational;

if (fractionalUSecGiven) {
if (args[6] instanceof RubyRational) {
RubyRational usecRat = (RubyRational) args[6];
RubyRational nsecRat = (RubyRational) usecRat.op_mul(context, runtime.newFixnum(1000));
double tmpNanos = nsecRat.getDoubleValue(context);
time.dt = dt.withMillis((long) (dt.getMillis() + (tmpNanos / 1000000)));
nanos = (long) tmpNanos % 1000000;
} else {
double micros = RubyNumeric.num2dbl(args[6]);
time.dt = dt.withMillis(dt.getMillis() + (long) (micros / 1000));
nanos = (long) Math.rint((micros * 1000) % 1000000);
}
// Ignores usec if 8 args (for compatibility with parse-date) or if not supplied.
if (args.length != 8 && args[6] != context.nil) {
if (args[6] instanceof RubyRational) {
RubyRational nsec = (RubyRational) ((RubyRational) args[6]).op_mul(context, runtime.newFixnum(1000));
long tmpNanos = (long) nsec.getDoubleValue(context);
time.dt = dt.withMillis(dt.getMillis() + (tmpNanos / 1_000_000));
nanos = tmpNanos % 1_000_000;
} else if (args[6] instanceof RubyFloat) {
double micros = ((RubyFloat) args[6]).getDoubleValue();
time.dt = dt.withMillis(dt.getMillis() + (long) (micros / 1000));
nanos = (long) Math.rint((micros * 1000) % 1_000_000);
} else {
int usec = int_args[4] % 1000;
int msec = int_args[4] / 1000;
@@ -1578,8 +1573,7 @@ private static RubyTime createTime(ThreadContext context, RubyClass klass, IRuby
}
}

if (nanos != 0)
time.setNSec(nanos);
if (nanos != 0) time.setNSec(nanos);

time.callInit(IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
time.setIsTzRelative(setTzRelative);
42 changes: 42 additions & 0 deletions test/jruby/test_time.rb
Original file line number Diff line number Diff line change
@@ -57,6 +57,48 @@ def test_far_future
t2 = now + 90000000000
assert_false t1 == t2
end

def test_end_of_day
time = time_change(Time.now,
:hour => 23,
:min => 59,
:sec => 59,
:usec => Rational(999_999_999, 1000)
)

assert_equal 23, time.hour
assert_equal 59, time.min
assert_equal 59, time.sec
assert_equal Time.now.zone, time.zone
assert_equal 999999999, time.nsec
end

def time_change(time, options) # from ActiveSupport
new_year = options.fetch(:year, time.year)
new_month = options.fetch(:month, time.month)
new_day = options.fetch(:day, time.day)
new_hour = options.fetch(:hour, time.hour)
new_min = options.fetch(:min, options[:hour] ? 0 : time.min)
new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : time.sec)

if new_nsec = options[:nsec]
raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
new_usec = Rational(new_nsec, 1000)
else
new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(time.nsec, 1000))
end

if time.utc?
::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
elsif time.zone
::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
else
raise ArgumentError, 'argument out of range' if new_usec >= 1000000
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), time.utc_offset)
end
end
private :time_change

end

class TestTimeNilOps < Test::Unit::TestCase

0 comments on commit 682626e

Please sign in to comment.