Aman-Mittal opened a new issue, #496:
URL: https://github.com/apache/fineract-backoffice-ui/issues/496

   ## Summary
   
   `formatDateToFineract()` in `src/app/core/utils/date-formatter.ts` parses 
its string input with `new Date(date)`. Per ECMAScript, a **date-only** string 
(`"2026-04-01"`) is parsed as **UTC midnight**, while the getters used to build 
the output — `getDate()`, `getMonth()`, `getFullYear()` — read **local** time. 
At any negative UTC offset the two disagree and the formatted date lands one 
day early:
   
   ```
   TZ=America/New_York   "2026-01-15"           ->  14 January 2026     ← wrong
   TZ=America/New_York   "2026-01-15T00:00:00"  ->  15 January 2026     ← 
correct
   TZ=Asia/Kolkata       "2026-01-15"           ->  15 January 2026
   TZ=Pacific/Auckland   "2026-01-15"           ->  15 January 2026
   UTC                   "2026-01-15"           ->  15 January 2026
   ```
   
   Values that originate from `ion-datetime` are unaffected — it emits a full 
*local* ISO timestamp (`2026-04-01T00:00:00`), which `new Date()` parses as 
local. The bug only bites where a **bare date-only string** is fed in, which 
happens whenever a form pre-fills from an API response and the user saves 
without re-picking that field.
   
   ## Live instance: editing an interest pause
   
   Introduced with the interest-pause edit flow (#283, PR #481, merged). In 
`interest-pause-form.component.ts`, `toFormDate()` produces a bare `YYYY-MM-DD` 
for the pre-filled pickers:
   
   - `formatArrayDate([2026, 4, 1])` → `"2026-04-01"`
   - `toIsoDate("2026-04-01T00:00:00Z")` → `.split('T', 1)[0]` → `"2026-04-01"`
   
   `onSubmit()` passes that straight to `formatDateToFineract()`.
   
   **Reproduction.** A user in `America/New_York` opens an existing 01–08 April 
interest pause, corrects only the **end** date, and saves. The PUT carries 
`startDate: "31 March 2026"` — a field they never touched, moved silently. That 
is the opposite of what the edit feature exists to do.
   
   ## Why the test suite does not catch it
   
   - `playwright.config.ts:108` pins `timezoneId: 'Asia/Kolkata'` (UTC+5:30).
   - Vitest inherits the runner's timezone, which is UTC on CI.
   
   Every offset ≥ 0 masks the defect. It surfaces immediately once the timezone 
moves west — the existing specs fail on their own assertions:
   
   ```console
   $ TZ=America/New_York npx ng run fineract-backoffice-ui:unit-test \
       --include='**/interest-pause-form.component.test.ts'
   
   × should post the formatted dates and navigate to the list
   × should put the formatted dates and navigate to the list in edit mode
   
   -  "startDate": "02 April 2026"      +  "startDate": "01 April 2026"
   -  "endDate":   "09 April 2026"      +  "endDate":   "08 April 2026"
   ```
   
   (The POST failure is test fidelity — the test feeds a bare string 
`ion-datetime` would not emit — while the PUT failure reflects a real runtime 
path.)
   
   ## Suggested fix
   
   Handle the date-only case explicitly in `formatDateToFineract`, so every 
call site is corrected at once:
   
   ```ts
   } else if (typeof date === 'string') {
     const ymd = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date);
     d = ymd ? new Date(+ymd[1], +ymd[2] - 1, +ymd[3]) : new Date(date);
   }
   ```
   
   `formatDateToFineract` has 55 call sites outside tests, so this wants its 
own review pass — but no caller can currently be relying on the UTC 
interpretation, since it is wrong for exactly the users it affects.
   
   The same latent pattern appears at `calendar-form.component.ts:207` and 
`:216`; worth sweeping in the same change.
   
   ## Regression guard
   
   Without one this returns silently. Either would do:
   
   - a `date-formatter` unit test asserting a bare `YYYY-MM-DD` formats as the 
same calendar day under a negative-offset `TZ`;
   - a CI job running the unit suite at, say, `TZ=America/New_York`, which 
would cover the whole app rather than one helper.
   
   ## Related
   
   Distinct from #358 (browser timezone vs. the tenant's validation timezone) — 
that one is about *which* timezone is authoritative, this one is a local/UTC 
parsing mismatch within a single timezone. Fixing either does not fix the 
other, but they touch the same code and are worth looking at together.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to