Skip to content

Conversation

@UjjawalPrabhat
Copy link
Contributor

@UjjawalPrabhat UjjawalPrabhat commented Oct 9, 2025

Requirements

  • PR title includes ticket number and conventional commit label.
  • My work is based on designs, which are linked or shown either in the Jira ticket or the description below.
  • My work includes tests or is validated by existing tests.

Summary

This PR fixes the issue where the immunization expiration date field was being saved with a one-day shift due to ISO-UTC conversion.

  • Introduces toDateOnlyString() utility to format dates as YYYY-MM-DD without timezone conversion
  • Updates the immunization form component to use toDateOnlyString() instead of .toISOString()
  • Adds comprehensive unit tests for the new utility (including edge cases and invalid inputs)
  • Updates existing form tests to include a regression test for O3-4970

Screen Recording:

Recording.2025-10-09.132330.mp4

Related Issue

https://openmrs.atlassian.net/browse/O3-4970

Other

  • Ensures FHIR compliance by formatting Immunization.expirationDate as a date type
  • Maintains backward compatibility with existing data records
  • All tests pass locally (34/34) including new regression tests

@VeronicaMuthee
Copy link
Contributor

@denniskigen @NethmiRodrigo kindly help in reviewing this PR.

ibacher
ibacher previously requested changes Oct 9, 2025
* toDateOnlyString(date); // Returns "2025-12-31"
* ```
*/
export const toDateOnlyString = (date: Date): string => {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need this date formatting utility. If we just need to set things to a specific date format, dayjs() can already do so.

const immunizationWithExpiration = {
vaccineUuid: '782AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
immunizationId: 'test-immunization-with-expiration',
vaccinationDate: new Date('2024-12-25').toString(),
Copy link
Member

Choose a reason for hiding this comment

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

Dates should still be formatted as ISO Strings here.

@UjjawalPrabhat
Copy link
Contributor Author

Hey @ibacher , @NethmiRodrigo , @VeronicaMuthee !
Implemented all the requested changes. Please let me know if any further changes required or if it is ready to merge.

@NethmiRodrigo
Copy link
Collaborator

@denniskigen @Muppasanipraneeth I remember in yesterday's call there was a discussion about this issue being related to the backend. Or am I mistaken?

@Muppasanipraneeth
Copy link
Contributor

@denniskigen @Muppasanipraneeth I remember in yesterday's call there was a discussion about this issue being related to the backend. Or am I mistaken?

yes @NethmiRodrigo the issue was backend could not pickup timezone

@UjjawalPrabhat
Copy link
Contributor Author

@NethmiRodrigo @Muppasanipraneeth @denniskigen

I'd like to clarify the approach I've taken in this PR.

My Solution is Timezone-Independent:

  • Instead of relying on timezone handling (frontend or backend), I've implemented the fix to be completely timezone-agnostic
  • The frontend now sends expiration dates as plain YYYY-MM-DD strings using dayjs(expirationDate).format('YYYY-MM-DD')
  • This eliminates any timezone conversion entirely - no matter what timezone the user or server is in, 31/12/2025 will always be sent as "2025-12-31"

Benefits of this approach:

  • FHIR compliant: Immunization.expirationDate should be date type (not dateTime)
  • Timezone independent: Works regardless of user/server timezone configuration
  • No backend changes needed: Backend receives clean date-only strings
  • Future-proof: Prevents similar timezone issues on other date-only fields

Question: Is this timezone-independent frontend approach the correct way to resolve O3-4970, or would you prefer a different strategy that involves backend timezone handling changes?

I believe this solution addresses the root cause while being the most robust approach, but I'm happy to adjust if there's a preferred architectural direction.

CC @ibacher @VeronicaMuthee

@denniskigen denniskigen requested a review from ibacher October 13, 2025 21:22
@UjjawalPrabhat
Copy link
Contributor Author

Hi @ibacher, just checking if you’ve had a chance to review this PR. Thanks!

UjjawalPrabhat and others added 5 commits October 29, 2025 23:03
- Add toDateOnlyString() utility function with robust error handling
- Update immunization form to use timezone-safe date formatting
- Replace .toISOString() with manual YYYY-MM-DD formatting
- Add comprehensive unit tests for date utility (11 test cases)
- Add regression test for O3-4970 in immunization form tests
- Ensure FHIR compliance for Immunization.expirationDate field
- Fix date shift bug where 31/12/2025 was saved as 30/12/2025

Fixes: https://openmrs.atlassian.net/browse/O3-4970
…ility

- Remove toDateOnlyString utility and its tests
- Import dayjs and replace toDateOnlyString(...) with dayjs(...).format('YYYY-MM-DD')
- Update form tests to expect ISO-formatted strings again
- Ensure existing tests pass without the custom utility
Add test coverage to verify expiration dates are sent as YYYY-MM-DD
date-only strings to prevent timezone conversion bugs.
@denniskigen denniskigen changed the title O3-4970: Fix immunization expiration date timezone conversion issue (fix) O3-4970: Use date-only format for immunization expiration dates Oct 29, 2025
@denniskigen denniskigen dismissed ibacher’s stale review October 29, 2025 20:14

Addressed in subsequent commits.

Copy link
Member

@denniskigen denniskigen left a comment

Choose a reason for hiding this comment

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

Thanks, @UjjawalPrabhat! LGTM.

@denniskigen denniskigen merged commit f576088 into openmrs:main Oct 29, 2025
5 of 6 checks passed
@UjjawalPrabhat UjjawalPrabhat deleted the O3-4970 branch October 30, 2025 06:29
NethmiRodrigo pushed a commit that referenced this pull request Oct 30, 2025
…#2779)

* O3-4970: Use date-only format for immunization expiration dates

- Add toDateOnlyString() utility function with robust error handling
- Update immunization form to use timezone-safe date formatting
- Replace .toISOString() with manual YYYY-MM-DD formatting
- Add comprehensive unit tests for date utility (11 test cases)
- Add regression test for O3-4970 in immunization form tests
- Ensure FHIR compliance for Immunization.expirationDate field
- Fix date shift bug where 31/12/2025 was saved as 30/12/2025

Fixes: https://openmrs.atlassian.net/browse/O3-4970

* Update packages/esm-patient-immunizations-app/src/immunizations/immunizations-form.test.tsx

Co-authored-by: Ian <[email protected]>

* fix(O3-4970): use dayjs for date-only formatting and remove custom utility

- Remove toDateOnlyString utility and its tests
- Import dayjs and replace toDateOnlyString(...) with dayjs(...).format('YYYY-MM-DD')
- Update form tests to expect ISO-formatted strings again
- Ensure existing tests pass without the custom utility

* Update packages/esm-patient-immunizations-app/src/immunizations/utils.ts

Co-authored-by: Nethmi Rodrigo <[email protected]>

* Add expiration date format tests

Add test coverage to verify expiration dates are sent as YYYY-MM-DD
date-only strings to prevent timezone conversion bugs.
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.

6 participants