Skip to content

Commit

Permalink
Merge pull request jruby#8002 from enebo/time_specs
Browse files Browse the repository at this point in the history
Time spec fixes
  • Loading branch information
enebo authored Nov 3, 2023
2 parents 765ba6c + 87f9377 commit c448bd5
Show file tree
Hide file tree
Showing 10 changed files with 39 additions and 52 deletions.
67 changes: 35 additions & 32 deletions core/src/main/java/org/jruby/RubyTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,14 +299,18 @@ public static DateTimeZone getTimeZoneFromUtcOffset(ThreadContext context, IRuby
n += (tmpBytes.get(min) * 10 + tmpBytes.get(min+1) - '0' * 11) * 60;
}

if (tmpBytes.get(0) != '+' && tmpBytes.get(0) != '-') return null;
if (!Character.isDigit(tmpBytes.get(1)) || !Character.isDigit(tmpBytes.get(2))) return null;
if (tmpBytes.realSize() >= 3) { // [+-]HH((MM)?SS)?
byte first = (byte) tmpBytes.get(0);
if (first != '+' && first != '-') return null;

n += (tmpBytes.get(1) * 10 + tmpBytes.get(2) - '0' * 11) * 3600;
if (!Character.isDigit(tmpBytes.get(1)) || !Character.isDigit(tmpBytes.get(2))) return null;

if (tmpBytes.get(0) == '-') {
if (n == 0) return DateTimeZone.UTC;
n = -n;
n += (tmpBytes.get(1) * 10 + tmpBytes.get(2) - '0' * 11) * 3600;

if (first == '-') {
if (n == 0) return DateTimeZone.UTC;
n = -n;
}
}

dtz = getTimeZoneWithOffset(runtime, "", n * 1000);
Expand All @@ -325,6 +329,10 @@ public static RaiseException invalidUTCOffset(Ruby runtime) {
return runtime.newArgumentError("\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
}

public static RaiseException invalidUTCOffset(Ruby runtime, IRubyObject value) {
return runtime.newArgumentError(str(runtime, "\"+HH:MM\", \"-HH:MM\", \"UTC\" or \"A\"..\"I\",\"K\"..\"Z\" expected for utc_offset: ", value));
}

// mri: time.c num_exact
private static RubyNumeric numExact(ThreadContext context, IRubyObject v) {
boolean typeError = false;
Expand Down Expand Up @@ -655,9 +663,9 @@ public RubyTime getlocal(ThreadContext context, IRubyObject off) {
}

if ((dtz = getTimeZoneFromUtcOffset(context, off)) == null) {
if ((zone = findTimezone(context, zone)) == null) throw invalidUTCOffset(runtime);
zone = findTimezone(context, zone);
RubyTime t = (RubyTime) dup();
if (!zoneLocalTime(context, zone, t)) throw invalidUTCOffset(runtime);
if (!zoneLocalTime(context, zone, t)) throw invalidUTCOffset(runtime, zone);
return t;
}
else if (dtz == DateTimeZone.UTC) {
Expand Down Expand Up @@ -1658,14 +1666,9 @@ private IRubyObject initializeNow(ThreadContext context, IRubyObject zone) {
if (dtz != null) {
this.setIsTzRelative(true);
} else {
if ((zone = findTimezone(context, zone)) != null) {
maybeZoneObj = true;
this.zone = zone;

dtz = DateTimeZone.UTC;
} else {
throw invalidUTCOffset(runtime);
}
this.zone = findTimezone(context, zone);
maybeZoneObj = true;
dtz = DateTimeZone.UTC;
}
}

Expand Down Expand Up @@ -1702,8 +1705,9 @@ private IRubyObject initializeNow(ThreadContext context, IRubyObject zone) {
dtz = getTimeZoneFromUtcOffset(context, zone);
if (dtz != null) {
this.dt = dt.withZoneRetainFields(dtz);
} else if ((zone = findTimezone(context, zone)) == null || !zoneTimeLocal(context, zone, this)) {
throw invalidUTCOffset(runtime);
} else {
zone = findTimezone(context, zone);
if (!zoneTimeLocal(context, zone, this)) throw invalidUTCOffset(runtime, zone);
}
}
}
Expand Down Expand Up @@ -1805,14 +1809,9 @@ private IRubyObject initialize(ThreadContext context, IRubyObject year, IRubyObj
if (dtz != null) {
this.setIsTzRelative(true);
} else {
if ((zone = findTimezone(context, zone)) != null) {
maybeZoneObj = true;
this.zone = zone;

dtz = DateTimeZone.UTC;
} else {
throw invalidUTCOffset(runtime);
}
this.zone = findTimezone(context, zone);
maybeZoneObj = true;
dtz = DateTimeZone.UTC;
}
}

Expand All @@ -1827,8 +1826,12 @@ private IRubyObject initialize(ThreadContext context, IRubyObject year, IRubyObj
dtz = getTimeZoneFromUtcOffset(context, zone);
if (dtz != null) {
dt = dt.withZoneRetainFields(dtz);
} else if ((zone = findTimezone(context, zone)) == null || !zoneTimeLocal(context, zone, this)) {
throw invalidUTCOffset(runtime);
} else {
if ((zone = findTimezone(context, zone)) == null) {
throw invalidUTCOffset(runtime);
} else if(!zoneTimeLocal(context, zone, this)) {
throw invalidUTCOffset(runtime, zone);
}
}
}
}
Expand All @@ -1841,8 +1844,9 @@ private static boolean maybeTimezoneObject(IRubyObject obj) {
}

private IRubyObject findTimezone(ThreadContext context, IRubyObject zone) {
RubyClass metaClass = getMetaClass();
return Helpers.invokeChecked(context, metaClass, "find_timezone", zone);
IRubyObject foundZone = Helpers.invokeChecked(context, getMetaClass(), "find_timezone", zone);
if (foundZone == null || foundZone.isNil()) throw invalidUTCOffset(context.runtime, zone);
return foundZone;
}

@JRubyMethod(name = {"utc", "gm"}, required = 1, optional = 9, checkArity = false, meta = true)
Expand Down Expand Up @@ -2173,8 +2177,7 @@ public static RubyTime timeZoneLocal(ThreadContext context, IRubyObject off, Rub

if ((dtz = getTimeZoneFromUtcOffset(context, off)) == null) {
zone = time.findTimezone(context, zone);
if (zone == null || zone.isNil()) throw invalidUTCOffset(context.runtime);
if (!zoneLocalTime(context, zone, time)) throw invalidUTCOffset(context.runtime);
if (!zoneLocalTime(context, zone, time)) throw invalidUTCOffset(context.runtime, zone);
return time;
} else if (dtz == DateTimeZone.UTC) {
return time.gmtime();
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/util/time/TimeArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,14 @@ private static int parseMonth(ThreadContext context, IRubyObject _month) {
try {
month = Integer.parseInt(monthStr);
} catch (NumberFormatException ex) {
throw context.runtime.newArgumentError("Argument out of range.");
throw context.runtime.newArgumentError("argument out of range.");
}
} else {
month = RubyNumeric.num2int(_month);
}

if (month < 1 || month > 12) {
throw context.runtime.newArgumentError("Argument out of range: for month: " + month);
throw context.runtime.newArgumentError("argument out of range: for month: " + month);
}

return month;
Expand Down Expand Up @@ -280,7 +280,7 @@ private void validateDayHourMinuteSecond(ThreadContext context) {
}

if ((second < 0 || second > 60) || (hour == 24 && second > 0)) {
throw context.runtime.newArgumentError("argument out of range for second");
throw context.runtime.newArgumentError("argument out of range");
}
}

Expand Down
1 change: 0 additions & 1 deletion spec/tags/ruby/core/time/at_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/tags/ruby/core/time/gm_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
fails(linux):Time.gm handles real leap seconds
fails:Time.gm raises an ArgumentError for out of range month
fails:Time.gm raises an ArgumentError for out of range second
2 changes: 0 additions & 2 deletions spec/tags/ruby/core/time/local_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/tags/ruby/core/time/localtime_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ fails:Time#localtime raises ArgumentError if the String argument is not in an AS
fails:Time#localtime with an argument that responds to #to_r coerces using #to_r
fails:Time#localtime does nothing if already in a local time zone
fails(not implemented, jruby/jruby#6161):Time#localtime raises ArgumentError if the String argument is not of the form (+|-)HH:MM
fails:Time#localtime returns a Time with a UTC offset specified as A-Z military zone
2 changes: 0 additions & 2 deletions spec/tags/ruby/core/time/mktime_tags.txt

This file was deleted.

7 changes: 1 addition & 6 deletions spec/tags/ruby/core/time/new_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,4 @@ fails(not implemented, jruby/jruby#6161):Time.new with a timezone argument Time-
fails(not implemented, jruby/jruby#6161):Time.new with a timezone argument #name method uses the optional #name method for marshaling
fails(not implemented, jruby/jruby#6161):Time.new with a timezone argument #name method cannot marshal Time if #name method isn't implemented
fails(not implemented, jruby/jruby#6161):Time.new with a timezone argument subject's class implements .find_timezone method calls .find_timezone to build a time object at loading marshaled data
fails(not implemented, jruby/jruby#6161):Time.new with a utc_offset argument raises ArgumentError if the String argument is not of the form (+|-)HH:MM
fails:Time.new raises an ArgumentError for out of range month
fails:Time.new raises an ArgumentError for out of range second
fails:Time.new with a utc_offset argument returns a Time with UTC offset specified as a single letter military timezone
fails:Time.new with a utc_offset argument raises ArgumentError if the string argument is J
fails:Time.new with a timezone argument :in keyword argument returns a Time with UTC offset specified as a single letter military timezone
fails(only during full spec run):Time.new with a utc_offset argument raises ArgumentError if the String argument is not of the form (+|-)HH:MM
1 change: 0 additions & 1 deletion spec/tags/ruby/core/time/now_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/tags/ruby/core/time/utc_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:Time#utc? does treat time with 'UTC' offset as UTC
fails:Time#utc? does treat time with Z offset as UTC
fails:Time#utc? does treat time with -00:00 offset as UTC
fails:Time.utc raises an ArgumentError for out of range month
fails:Time.utc raises an ArgumentError for out of range second

0 comments on commit c448bd5

Please sign in to comment.