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

Implement ZonedDateTime.until() and since() in polyfill #1116

Merged
merged 1 commit into from
Nov 5, 2020

Conversation

ptomato
Copy link
Collaborator

@ptomato ptomato commented Nov 4, 2020

Note that the DifferenceZonedDateTime abstract operation is not final:
there is one edge case that is broken in the polyfill, which is that the
since() method needs to use this as the relative date for rounding.
There is a test for that which is skipped.

A follow-up commit will fix this case and add spec text for the algorithm.

Co-authored-by: Justin Grant [email protected]

See: #569

@codecov
Copy link

codecov bot commented Nov 4, 2020

Codecov Report

Merging #1116 into main will decrease coverage by 2.71%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1116      +/-   ##
==========================================
- Coverage   93.55%   90.83%   -2.72%     
==========================================
  Files          19       17       -2     
  Lines        7961     8741     +780     
  Branches     1264     1232      -32     
==========================================
+ Hits         7448     7940     +492     
- Misses        506      790     +284     
- Partials        7       11       +4     
Flag Coverage Δ
test262 ?
tests 90.83% <ø> (+1.39%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
polyfill/lib/shim.mjs
polyfill/lib/legacydate.mjs
polyfill/lib/slots.mjs
polyfill/lib/intrinsicclass.mjs
lib/calendar.mjs 77.59% <0.00%> (ø)
lib/plaindatetime.mjs 90.84% <0.00%> (ø)
lib/temporal.mjs 100.00% <0.00%> (ø)
lib/ecmascript.mjs 94.29% <0.00%> (ø)
lib/plaindate.mjs 87.08% <0.00%> (ø)
lib/plaintime.mjs 89.73% <0.00%> (ø)
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4b94392...747fbbe. Read the comment docs.

Copy link
Collaborator

@justingrant justingrant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have time today to closely review the algorithm line-by-line, but I left a bunch of comments, mostly related to our discussion in #993. If your plan is to address those comments in a follow-up, then this PR seems OK to merge now.

polyfill/lib/ecmascript.mjs Outdated Show resolved Hide resolved
polyfill/lib/zoneddatetime.mjs Outdated Show resolved Hide resolved
polyfill/lib/zoneddatetime.mjs Outdated Show resolved Hide resolved
polyfill/lib/ecmascript.mjs Outdated Show resolved Hide resolved
const later = ZonedDateTime.from('2019-10-29T10:46:38.271986102-03:00[America/Santiago]');
['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'].forEach((largestUnit) => {
const diff = later.since(earlier, { largestUnit });
it(`earlier.since(later, ${largestUnit}) == later.since(earlier, ${largestUnit}).negated()`, () =>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: This test won't work for largestUnit of 'years' or 'months' for some pairs of dates. If it works for this pair, that's just luck. The only guarantee that you can make given our decision of (A) in #993 (comment) is that if d = a.since(b) then a.subtract(d).equals(b). AFAIK there are no other guarantees that can be made for all pairs of values.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm doing for the DateTime and Date versions of these tests is to run different tests for months/years vs. all other units. And I use pairs of values that trigger the behavior difference. If you're not seeing failures in this test, then I'd suggest changing your earlier/later values to ones where behavior will vary by direction.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed this part to the following, which I think should be correct regardless of whether #993 has landed:

    const earlier = ZonedDateTime.from('1976-11-18T15:23:30.123456789-03:00[America/Santiago]');
    const later = ZonedDateTime.from('2019-10-29T10:46:38.271986102-03:00[America/Santiago]');
    // The interchangeability of since() and until() holds for time units only
    ['hours', 'minutes', 'seconds'].forEach((largestUnit) => {
      const diff = later.since(earlier, { largestUnit });
      it(`earlier.since(later, ${largestUnit}) == later.since(earlier, ${largestUnit}).negated()`, () =>
        equal(`${earlier.since(later, { largestUnit })}`, `${diff.negated()}`));
      it(`earlier.until(later, ${largestUnit}) == later.since(earlier, ${largestUnit})`, () =>
        equal(`${earlier.until(later, { largestUnit })}`, `${diff}`));
      it(`${largestUnit} difference symmetrical with regard to negative durations`, () => {
        assert(earlier.subtract(diff.negated()).equals(later));
        assert(later.add(diff.negated()).equals(earlier));
      });
    });
    // For all units, add() undoes until() and subtract() undoes since()
    ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'].forEach((largestUnit) => {
      const diff1 = earlier.until(later, { largestUnit });
      const diff2 = later.since(earlier, { largestUnit });
      it(`earlier.add(${diff1}) == later`, () => assert(earlier.add(diff1).equals(later)));
      it(`later.subtract(${diff2}) == earlier`, () => assert(later.subtract(diff2).equals(earlier)));
    });

If I have time later, I'll try to add a few test cases that trigger calendar or time zone differences.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I did a similar split in #1123.

polyfill/test/zoneddatetime.mjs Outdated Show resolved Hide resolved
polyfill/test/zoneddatetime.mjs Show resolved Hide resolved
polyfill/test/zoneddatetime.mjs Show resolved Hide resolved
describe('Maths', () => {
const earlier = ZonedDateTime.from('1976-11-18T15:23:30.123456789-03:00[America/Santiago]');
const later = ZonedDateTime.from('2019-10-29T10:46:38.271986102-03:00[America/Santiago]');
['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'].forEach((largestUnit) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd think you need 2-4 more variations of this test to test reversibility with DST involved. If there's disambiguation at the point where you're done adding days and need to add the time, then behavior will vary based on the direction of the operation. It's possible that those tests already exist, so can ignore this comment if so. But there's a lot of confusing logic around the interplay between dates, times, and DST and it's easy to get it wrong. I think that you'll know you have good values of earlier and later when a.add(d).equals(b)===true but b.subtract(d).equals(a)===false and the results are 1 or 2 hours apart.

For variations, it probably needs one for the transition on the earlier side, and one on the later side, and then a test of both forward and backward transitions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I'll get this done tonight, but let's open an issue tomorrow to add more test coverage.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1140

@@ -1473,6 +2124,263 @@ describe('ZonedDateTime', () => {
});
});

describe('math around DST', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that since and until will have different behavior around DST transitions, some (all?) of the added tests below probably be cloned or refactored to test since too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, I don't think I'll get this done tonight either, but let's include this in the issue to add more test coverage.

@ptomato
Copy link
Collaborator Author

ptomato commented Nov 4, 2020

I wasn't intending to take the changes from #993 into account in these tests when I wrote them yesterday, but maybe you're right that that would be better, or at least write them such that they would pass in both cases. I'll see about updating this after I'm finished with with().

@justingrant
Copy link
Collaborator

I wasn't intending to take the changes from #993 into account in these tests when I wrote them yesterday, but maybe you're right that that would be better

Sounds good. If you're not going to merge this PR today (which would probably be helpful for my PR anyways), then I'd suggest to merge the #993 fix in tonight/tomorrow and then you may be able to copy/paste both tests and logic from my PR if it helps accelerate things on the ZDT end. But I won't plan to make any ZDT changes in my PR. (Although I will be changing differenceDate and the subtract methods in various types so there still may be some tests that break on your end.) Does this sound like an OK plan?

@ptomato
Copy link
Collaborator Author

ptomato commented Nov 5, 2020

We do need to make absolutely certain this is merged tomorrow, so that I can cut a release of the polyfill in preparation for Friday. If it gets into conflict with your changes, then maybe I can remove the failing tests from this PR at that point so that we at least have an implementation that works with most options.

@justingrant
Copy link
Collaborator

Sounds good. I'm wrapping up #993 PR now... just need to delete a bunch of dateSubtract stuff out of Calendar. Should have it posted within the hour. BTW, turned out that #1111 didn't break any tests (at least not any that I know about!).

Also I did end up fixing a few ZDT things like enabling skipped order-of-operations tests and removing the subtraction AO. But otherwise steered clear of ZDT to reduce conflicts.

@ptomato
Copy link
Collaborator Author

ptomato commented Nov 5, 2020

I've managed to fix the edge case that was broken, so I've enabled the remaining test now.

@justingrant
Copy link
Collaborator

Heads up @ryzokuken and @Ms2ger - once #1123 is merged, it's likely that some tests in this PR will break because #1123 changes the behavior of subtract and since for most Temporal types. It shouldn't actually break this PR's implementation (unless this PR has a bug that was hidden by existing behavior) but some tests in this PR may need new "expected" data to match the (now correct) output of subtract, since, and ES.DateDifference from #1123.

I'll leave it up to you guys and @ptomato to figure out how to order the merges, but I assume it'd be better to merge #1123 before this PR because this #1123 is lower-level and larger in scope than this PR's changes. And also because it will probably be faster for @ptomato to fix any of this PR's tests that are broken by #1123 than for me to figure out why his tests are breaking! ;-)

Copy link
Collaborator

@justingrant justingrant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, the since implementation should be updated to match the #993 fixes. I commented inline where exactly the needed changes are, based on #1023's implementation of DateTime.prototype.since.

Otherwise this looks good!

polyfill/lib/zoneddatetime.mjs Outdated Show resolved Hide resolved
polyfill/lib/zoneddatetime.mjs Show resolved Hide resolved
polyfill/lib/zoneddatetime.mjs Outdated Show resolved Hide resolved
polyfill/lib/zoneddatetime.mjs Outdated Show resolved Hide resolved
polyfill/lib/ecmascript.mjs Show resolved Hide resolved
Copy link
Member

@ryzokuken ryzokuken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RSLGTM

@ptomato ptomato merged commit 3aa42c3 into main Nov 5, 2020
@ptomato ptomato deleted the zoneddatetime-5 branch November 5, 2020 23:09
@ptomato
Copy link
Collaborator Author

ptomato commented Nov 5, 2020

I believe this is updated to reflect the order-of-operations change, merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants