users expire at midnight in tenant timezone instead of UTC #2943
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.



Fix expiration date issues.
Problems
The expiration date field shows one day ahead for the timezone, which is already the next day (Pacific/Fakaofo). This happens because the expiration date is not saved at the end of the day, it is saved with a time shift based on your timezone (e.g. 2025-08-07T20:59:59.999Z). The expiration date must display the same date for all timezones (UIU-3352).Approach
1). Store dates in UTC - so "07/28/2025" becomes "2025-07-28T23:59:59.999Z" (end of day UTC)
2). Display dates without timezone conversion - so every timezone sees "07/28/2025"
3). Apply timezone logic only for expiration checking - convert UTC stored date to local timezone for comparison
Save dates as UTC end of day usingdayjs.utc(e.g. 2025-08-07T23:59:59.999Z), so that the expiration date field will display the same year, month, and day for all timezones (implemented in theparseExpirationDatefunction).dayjs.utc(e.g. 2025-08-07T23:59:59.999Z), so that the expiration date field will display the same year, month, and day for all timezones (implemented in theparseExpirationDate).isUserExpired), also usedayjs.utcto avoid time shifting. This will allow having the correct year, month, and day.now), since without.tz(...), the timezone selected in the settings will not be taken into account, instead the local system/browser timezone will be taken into account.now..format('L')to.format('YYYY-MM-DD')in thesetRecalculatedExpirationDate.momenttodayjseverywhere for the expiration date functionality.Description
Based on the conversation summary and the current state of the files, I can describe what was accomplished in this comprehensive timezone bug fix:
What Was Done
Consistent Display: FormattedDate components use timeZone="UTC" to show the same date across all timezones
In EditUserInfo.js:
parseExpirationDate(): Converts input dates to UTC ISO strings for storagecalculateNewExpirationDate(): Performs date arithmetic in tenant timezonegetNowAndExpirationEndOfDayInTenantTz(): Creates timezone-aware comparison objectsisUserExpired()/willUserExtend(): Timezone-aware expiration checksIn getProxySponsorWarning.js:
.format('L')to.format('YYYY-MM-DD')to prevent ambiguous date parsing that caused wrong dates to displayWhy This Approach Was Chosen
UTC Storage + Timezone-Aware Logic Pattern
This hybrid approach provides:
Example of the Fix in Action
For a Vancouver user (UTC-8) with expiration date "2025-07-29":
Approach
TODOS and Open Questions
Learning
Pre-Merge Checklist
Before merging this PR, please go through the following list and take appropriate actions.
If there are breaking changes, please STOP and consider the following:
Ideally all of the PRs involved in breaking changes would be merged in the same day to avoid breaking the folio-testing environment. Communication is paramount if that is to be achieved, especially as the number of intermodule and inter-team dependencies increase.
While it's helpful for reviewers to help identify potential problems, ensuring that it's safe to merge is ultimately the responsibility of the PR assignee.