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: date-picker bug for negative UTC timezones attempt 3 #6261

Merged
merged 15 commits into from
May 24, 2023

Conversation

LinHuiqing
Copy link
Contributor

@LinHuiqing LinHuiqing commented May 4, 2023

Problem

(taken from #6096)

(taken from #6025)
Date picker was using the midnight of the date picked and taking into account the timezone where the user is filling in the form. However, it does not make sense to do so as users will be picking particular dates rather than timings, and the understanding of the different timezones should be established as part of the question.

However, bug fix in PR #6025 almost caused an incident as the fix removed converting to UTC on the date picker itself, which was causing the selection offset bug.

Unfortunately, datepicker bug fix attempt #2 (#6096) caused an actual incident due to incorrect date validation for the pastOnlyValidator (post-mortem).

Solution

For bug caused by #6096 - Restore original date validators.

Breaking Changes

  • No - this PR is backwards compatible. Custom dates were already saved in midnight UTC in the DB.

Improvements:

  • Cast time to UTC only right before submitting custom date so the conversion will be completely invisible to users
  • Cast time to local timezone before being shown on the frontend so the frontend timezone will be consistent

Bug Fixes:

  • Users with negative UTC timezones will now have their date fields correctly reflecting the dates selected on their date pickers
  • zonedTimeToUTC was converting the timings to UTC and thus the actual date being referred to will not be preserved for respondents in negative UTC timezones. Implemented normalizeDateToUtc to ensure the actual date numbers are are preserved.

Before & After Screenshots

BEFORE:

Screen.Recording.2023-03-31.at.3.18.31.AM.mov

AFTER:

Disallow past dates:

Screen.Recording.2023-04-13.at.2.48.49.PM.mov

Disallow future dates:

Screen.Recording.2023-04-13.at.5.08.17.PM.mov

Custom date range:

Screen.Recording.2023-04-13.at.5.11.57.PM.mov

Tests

To ensure that all our bases are covered, try to test the most extreme timezones. Here are the suggested timezones:

  • Most common use case: Singapore - Singapore (UTC +08)
  • Negative: Alofi - Niue (UTC -11)
  • Positive: Wellington - New Zealand (UTC +12)

Preparation:

  • Create a form with a date field and open the form.

For the tests below, timezones A and B refer to the positive and negative timezones mentioned above, in any order.

i) Ensure that date picker for date field with "Disallow past dates" option exhibits expected behaviour:

    • Set your timezone as A.
    • On the admin panel, refresh, select and save the "Disallow past dates" option for the date field.
    • On the respondent form, refresh and open the date picker. Only the current and future dates of the timezone should be shown.
    • Select a date. The appropriate date should be reflected in the date field.
    • Change your device's timezone to B.
    • Repeat tasks 3-4.
    • Repeat tasks 2-4.
    • Change your device's timezone to A.
    • Repeat tasks 3-4.

ii) Ensure that date picker for date field with "Disallow future dates" option exhibits expected behaviour:

    • Set your timezone as A.
    • On the admin panel, refresh, select and save the "Disallow future dates" option for the date field.
    • On the respondent form, refresh and open the date picker. Only the current and future dates of the timezone should be shown.
    • Select a date. The appropriate date should be reflected in the date field.
    • Change your device's timezone to B.
    • Repeat tasks 3-4.
    • Repeat tasks 2-4.
    • Change your device's timezone to A.
    • Repeat tasks 3-4.

iii) Ensure that date picker for date field with "Custom date range" option exhibits expected behaviour:

    • Set your timezone as A.
    • On the admin panel, refresh and select the "Custom date range" option for the date field.
    • Select a start date.
    • Open the end date field date picker. Only the dates on or after the selected start date should be selectable.
    • Select an end date.
    • Save the selected date range. Optionally, check that the dates saved in the DB are in UTC.
    • On the respondent form, refresh and open the date picker. Only the dates in the selected date range should be selectable.
    • Select a date. The respective date should be reflected in the date field.
    • Change your device's timezone to B.
    • Repeat tasks 7-8.
    • Repeat task 2. Ensure that the start and end dates remain the same.
    • Update the start and end dates for the date field. Save it.
    • Repeat tasks 7-8.
    • Change your device's timezone to A.
    • Repeat tasks 7-8.

iv) Ensure that email mode forms with date field still work:

  • Repeat test set (i), making sure to select the current date using the date picker and submitting.
  • Repeat test set (ii), making sure to select the current date using the date picker and submitting.
  • Repeat test set (iii), making sure to:
    • Select the start date using the date picker and submitting.
    • Select the end date using the date picker and submitting.

Note: Here's how to set your Mac's timezone.

Design/ product question: Should "Disallow past dates" and "Disallow future dates" be taking the past / future based on the admins' timezone, specified timezone or the users' timezone? Also, even when we have decided on the previous question, does it even make sense if the concept of time is not considered? E.g. if the recurring event I want to organise is at 10am, our date picker won't be able to know that so if we have a timezone in mind, it won't "filter" properly. Currently, it's simply implemented based on the users' timezone so its not disorienting.

@LinHuiqing LinHuiqing changed the title Fix/date picker timezone fix: date-picker bug for negative UTC timezones attempt #3 May 4, 2023
@LinHuiqing LinHuiqing marked this pull request as ready for review May 4, 2023 02:52
@LinHuiqing LinHuiqing requested review from foochifa and tshuli May 4, 2023 02:54
@LinHuiqing LinHuiqing changed the title fix: date-picker bug for negative UTC timezones attempt #3 fix: date-picker bug for negative UTC timezones attempt 3 May 4, 2023
@LinHuiqing
Copy link
Contributor Author

For pastOnlyValidator and futureOnlyValidator, I wonder if the conversions done are even warranted actually, especially considering that answer from response is a DD MMM YYYY string with no time in it. For now, the code change in this PR does not make any changes for this, but just something for discussion for correctness!

@karrui
Copy link
Contributor

karrui commented May 8, 2023

Looking at the main problem, I would warrant that the client should not need to know about any server implementation.
The following inputs -> outputs should be handled on the client:

no past dates: prevent past dates according to client time
no future dates: prevent future dates according to client time
date range: accept as long as client date selected in range.

All client should do is to set the date object to start of day selected before passing to the client, no need to convert to UTC. The futureOnlyValidator and pastOnlyValidator should be able to handle any day range as long as the time is a start of day.

@LinHuiqing
Copy link
Contributor Author

LinHuiqing commented May 8, 2023

Looking at the main problem, I would warrant that the client should not need to know about any server implementation. The following inputs -> outputs should be handled on the client:

no past dates: prevent past dates according to client time no future dates: prevent future dates according to client time date range: accept as long as client date selected in range.

All client should do is to set the date object to start of day selected before passing to the client, no need to convert to UTC. The futureOnlyValidator and pastOnlyValidator should be able to handle any day range as long as the time is a start of day.

So regarding this, should we stick to the implementation in this PR as of now and open a new issue for handling date 'normalisation' on backend?

FYI:

  • Did some investigation on the custom date range saving - the dates are saved in UTC midnight in production.
  • Date field responses for both storage mode and email mode forms are in strings (DD MMM YYYY).

Copy link
Contributor

@karrui karrui left a comment

Choose a reason for hiding this comment

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

seems correct, lgtm. Can we have some unit tests on the date util functions to ensure that the two functions work as expected?

@LinHuiqing
Copy link
Contributor Author

seems correct, lgtm. Can we have some unit tests on the date util functions to ensure that the two functions work as expected?

ah yes, we should have that in place before pushing! thanks @karrui will add it in 👍 🌮

@LinHuiqing
Copy link
Contributor Author

seems correct, lgtm. Can we have some unit tests on the date util functions to ensure that the two functions work as expected?

ah yes, we should have that in place before pushing! thanks @karrui will add it in 👍 🌮

Regarding unit tests for date utils, I'm finding it particularly hard to test normalizeDateToUtc and loadDateFromNormalizedDate because there is no timezone information stored in Date so it implicitly uses local time when methods like getFullYear, getMonth and getDate are used, but it is what we're passing in as input... Migrating to use strings is getting more and more tempting 😭

@karrui
Copy link
Contributor

karrui commented May 16, 2023

because there is no timezone information stored in Date

Can try mocking with timezone-mock

@LinHuiqing
Copy link
Contributor Author

because there is no timezone information stored in Date

Can try mocking with timezone-mock

Thanks for the suggestion! It works

@LinHuiqing LinHuiqing force-pushed the fix/date-picker-timezone branch from 5eaa50a to 51a8169 Compare May 16, 2023 08:51
@LinHuiqing
Copy link
Contributor Author

LinHuiqing commented May 16, 2023

Rebased to develop and force pushed so that Playwright Tests can pass. New commits since last review are "fix: normalizeDateToUtc to return Date object" and after.

@LinHuiqing LinHuiqing requested a review from karrui May 16, 2023 09:27
const localDate = new Date(Date.parse(dateString))
const utcDate = new Date(Date.parse(`${dateString}+00:00`))

const result = DateUtils.normalizeDateToUtc(localDate)
Copy link
Contributor

Choose a reason for hiding this comment

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

Might want to assert before and after the util is called to ensure dates are different first

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm I don't think this is especially valuable as an assertion as ideally the test should still pass when the local time is UTC. But I get it that there is no value in the test if the local time and UTC time is the same, I guess. Will it be better that this test is removed or that the local time here is set as SGT?

Copy link
Contributor

Choose a reason for hiding this comment

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

The rationale is to assert that the mock date library is also working, just in case :P

Copy link
Contributor Author

Choose a reason for hiding this comment

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

haha okay, I'll add the assertion for the positive/negative utc tests then! yea when i tried the library I did print the dates to make sure hahaha

Copy link
Contributor Author

Choose a reason for hiding this comment

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

checks added here: d232fad

@LinHuiqing
Copy link
Contributor Author

Note:
Playwright tests failed twice for commit d232fad due to being unable to install Playwright browsers: actions/runner-images#7048

@LinHuiqing LinHuiqing requested a review from karrui May 17, 2023 07:41
Copy link
Contributor

@karrui karrui left a comment

Choose a reason for hiding this comment

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

lgtm~

@LinHuiqing LinHuiqing merged commit a21f0e1 into develop May 24, 2023
@LinHuiqing LinHuiqing deleted the fix/date-picker-timezone branch May 24, 2023 05:28
@LinHuiqing LinHuiqing mentioned this pull request May 24, 2023
39 tasks
LinHuiqing added a commit that referenced this pull request May 24, 2023
* fix: date-picker bug for negative UTC timezones attempt 3 (#6261)

* fix: remove timezone from datepicker

* fix: datepicker bugs due to timezones

- (FE) normalize dates to UTC before storing in DB
- (FE) load normalized dates to local timezone
- (BE) remove adjustments due to timezone

* docs: futureOnly and pastOnly validators

* refactor: allow null inputs for new date util fns

* fix: date normalization fns to use date as numbers

* refactor: remove unnecessary var assignment

* fix: unset date validation

* fix: compare to dates in earliest & latest tzs

* fix: date validation bug in release v6.41.0

* fix: restore original date validators

* fix: normalizeDateToUtc to return Date object

* test: frontend date utils

* build(deps): add timezone-mock to mock local time

* test: date utils in the most extreme timezones

* test: add check to ensure that timezone-mock works

* chore: bump version to v6.53.0
@LinHuiqing LinHuiqing mentioned this pull request May 25, 2023
23 tasks
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.

2 participants