Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix time precision with fractional seconds as Rational #5564

Merged
merged 1 commit into from Jan 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 19 additions & 6 deletions core/src/main/java/org/jruby/RubyTime.java
Expand Up @@ -1743,13 +1743,26 @@ private RubyTime initTime(ThreadContext context, IRubyObject[] args, boolean gmt

// 1.9 will observe fractional seconds *if* not given usec
if (args[5] != context.nil && args[6] == context.nil) {
double secs = RubyFloat.num2dbl(context, args[5]);
if (secs < 0 || secs >= TIME_SCALE) {
throw runtime.newArgumentError("argument out of range.");
if (args[5] instanceof RubyRational) {
RubyRational rat = (RubyRational) args[5];
if (rat.isNegative()) {
throw runtime.newArgumentError("argument out of range.");
}
RubyRational nsec = (RubyRational) rat.op_mul(context, runtime.newFixnum(1_000_000_000));
long full_nanos = nsec.getLongValue();
long millis = full_nanos / 1_000_000;

nanos = full_nanos - millis * 1_000_000;
instant = chrono.millis().add(instant, millis % 1000);
} else {
double secs = RubyFloat.num2dbl(context, args[5]);
if (secs < 0 || secs >= TIME_SCALE) {
throw runtime.newArgumentError("argument out of range.");
}
int int_millis = (int) (secs * 1000) % 1000;
instant = chrono.millis().add(instant, int_millis);
nanos = ((long) (secs * 1000000000) % 1000000);
}
int int_millis = (int) (secs * 1000) % 1000;
instant = chrono.millis().add(instant, int_millis);
nanos = ((long) (secs * 1000000000) % 1000000);
}

dt = dt.withMillis(instant);
Expand Down
15 changes: 15 additions & 0 deletions test/jruby/test_time.rb
Expand Up @@ -46,6 +46,21 @@ def test_nsec_rounding # GH-843
assert_false t1 == t2
end

def test_usec_as_rational
# 8.123456 is known to fail with Rational.to_f
sec = 8 + Rational(123456, 1_000_000)
t1 = Time.utc(2019,1,18,19,37, sec)
assert_equal 8, t1.sec
assert_equal 123456000, t1.nsec
end

def test_nsec_as_rational
sec = 8 + Rational(123456789, 1_000_000_000)
t1 = Time.utc(2019,1,18,19,37, sec)
assert_equal 8, t1.sec
assert_equal 123456789, t1.nsec
end

def test_large_add # GH-1779
t = Time.local(2000, 1, 1) + (400 * 366 * 24 * 60 * 60)
assert_equal 2400, t.year
Expand Down