Round a fractional offset given as a string - #190
Open
youdie006 wants to merge 1 commit into
Open
Conversation
date_zone_to_diff returns a Rational for a fractional-hour zone with
more than two digits, and offset_to_sec's string branch discarded it:
DateTime.new(2001,2,3, 0,0,0, '+00.123') #=> offset 0
DateTime.new(2001,2,3, 0,0,0, 442.8/86400) #=> offset 443
DateTime.new(2001,2,3, 0,0,0, Rational(2214, 5*86400))
#=> offset 443
The same quantity, three ways, two answers. The Float branch rounds and
warns "fraction of offset is ignored", and the Rational branch does the
same; only the string branch returned 0 with "invalid offset is
ignored".
Round it the way the two sibling branches already do. Zones that
date_zone_to_diff rejects are still rejected, and the DAY_IN_SECONDS
range check still runs on the rounded value.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The inconsistency
date_zone_to_diffreturns a Rational for a fractional-hour zone with morethan two digits (
ext/date/date_parse.c:529-535), and the comment just above itsays that is intended — "no over precision for offset; 10**-7 hour = 0.36
milliseconds should be enough" (
:506-508).offset_to_sec's string branch threw that away:if (!FIXNUM_P(vs)) return 0;at
ext/date/date_core.c:2639.Its two sibling branches in the same function do the opposite — they round and
warn.
T_FLOATat:2590-2592andT_RATIONALat:2621-2623both emitrb_warning("fraction of offset is ignored").So one quantity, three ways, two answers:
442.8 seconds either way. The string form — the only one a user actually types —
is the one that silently becomes
+00:00.Not currently tested
git ls-files -z test | xargs -0 grep -nE "['\"][-+][0-9]{2}\.[0-9]+['\"]"returnsnothing: no test passes a dotted zone as an offset argument. The
.123hits inthe suite are sub-second fractions of the time (
'19990523235521.123456+0900'),not zones, and
grep -n 'fraction of offset' test/finds nothing.The one fractional zone that is tested,
'[-9.50]'attest_date_parse.rb:137-138,has two digits, so it takes
date_zone_to_diff'sn <= 2Integer path(
date_parse.c:524-528) — already consistent, and untouched by this. The Rationalpath is what was untested.
The change
Round it, exactly as the sibling branches do.
k_rational_p,f_round,f_eqeq_pandrb_warningare all already used in this file.The
k_rational_pguard matters:date_zone_to_diffreturnsQnilfor a zone itrejects, and without the guard that
nilreachesf_round.Not a widening
'+24:00'and'+99:00'still give 0 —date_zone_to_diffrejects them beforethis code runs.
'+00:00'→ 0,'+01.5'→ 5400,'+9.50'→ 34200,'+00.1'→360,
'+00.12'→ 432,'+23:59:59'→ 86399 are all unchanged. Then < -DAY_IN_SECONDS || n > DAY_IN_SECONDScheck at:2642still runs on therounded value, and
'+23.9999999'rounds to exactly 86400, which the inclusiveguard accepts — consistent with
Rational(1,1)being legal per the existingtest_civil__offsetat:196-197.Direction
I want to be straight about the tension here. Read shallowly, the recent commits
on these files are a tightening trend (#183's range check, #188's commercial-week
validation,
c98d85dverifying argument classes), which would argue for making thestring branch keep rejecting.
I do not think that is the right read. #183's own commit message frames its defect
as "the Integer 2 is rejected, but Rational(2,1) is the same quantity" — the
principle is consistency between representations of one quantity, which is exactly
this. And rounding is the long-standing behaviour here:
rb_warning("fraction of offset is ignored")already exists at:2592,:2623and:3349. The stringbranch is the deviation, not the rule.
If you would rather go the other way and make Float and Rational reject too, that
is a coherent position and I am happy to write that instead.
Verification
errors. Pristine control run: same 148 tests with exactly one failure, mine —
so nothing else changes behaviour.
since TruffleRuby ships its own
date. It does compile this C extension viaSulong, and I ran it: with master's code
'+00.123'gives 0 and warns "invalidoffset is ignored"; with this patch it gives 443 and warns "fraction of offset is
ignored", while
'+24:00'/'+99:00'stay 0 and'+01.5'/'+23:59:59'areunchanged. So the truffleruby job is fixed by this too rather than broken by it.
warning fails; dropping the
k_rational_pguard raisesNoMethodError: undefined method 'round' for nilon the'+24:00'row.One thing I deliberately left out
DateTime.parse('2001-02-03T00:00:00+00.123')goes throughdt_new_by_frags,which does
of = NUM2INT(t)atdate_core.c:8519and truncates to 442. Soafter this change
DateTime.parseandDateTime.newdiffer by one second on thesame zone string.
That is a real but separate inconsistency in a different function, and bundling it
would make this patch harder to judge. Happy to follow up. (Same spot also narrows
before its range check at
:8520, the inverse of #183's principle — currentlyunreachable, since
date_zone_to_diffcaps output near 3.6e8.)Disclosure
I used an AI assistant to help find and prepare this change. I reviewed and tested
it myself, and the outputs above are from runs I performed.