fix(mp): correct timezone handling on MP datetime writes#15
Merged
Conversation
MP stores datetimes as wall-clock values in the domain's configured time
zone, not UTC. Existing write paths in GroupService and FamilyService tagged
values as UTC (via `${date}T00:00:00Z` or `new Date().toISOString()`),
which caused saved records to drift by the offset between the Node server's
local zone and MP's domain zone. Edits compounded the drift on each save.
- Add DomainTimezoneService — singleton wrapping getDomainInfo() with
Windows->IANA mapping and SQL datetime conversion (toMpSqlDatetime,
parseMpDatetime).
- Add shared server action getMpTimezone() for client-side display.
- Fix GroupService.createGroup/updateGroup to route Start_Date / End_Date /
Promotion_Date through the service.
- Fix FamilyService Participant_Start_Date and Donor Setup_Date writes to
use MP-TZ wall-clock instead of new Date().toISOString().
- Update groupService.test.ts: mock getDomainInfo, reset both singletons in
beforeEach, assert MP-SQL format, add round-trip regression proving three
consecutive saves of the same date do not shift.
- Add reference doc .claude/references/ministryplatform.datetimehandling.md.
- Update CLAUDE.md with Key Development Practice #12 + reference link.
Tests: 16 new in domainTimezoneService.test.ts, 1 round-trip regression in
groupService.test.ts. Full suite passes (664/664) under TZ=UTC and
TZ=America/Los_Angeles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
${date}T00:00:00Z,new Date().toISOString()) which caused saved records to drift by the offset between the Node server's local zone and MP's domain zone — and edits compounded the drift on each save.DomainTimezoneService(singleton, Windows→IANA mapping,toMpSqlDatetime/parseMpDatetime), agetMpTimezone()shared server action, fixes the offending writes inGroupServiceandFamilyService, and ships a reference doc + CLAUDE.md rule so future MP date work doesn't re-introduce the pattern.Changes
src/services/domainTimezoneService.ts— singleton boundary service; only path that readsMPHelper.getDomainInfo().TimeZoneName.src/services/domainTimezoneService.test.ts— 16 tests covering Windows→IANA mapping, caching, concurrent dedupe, wall-clock vs instant inputs, and a server-TZ-independent regression.src/components/shared-actions/domain.ts—getMpTimezone()server action for client-sideIntl.DateTimeFormatrendering.src/services/groupService.ts—Start_Date/End_Date/Promotion_Datenow route throughtoMpSqlDatetime.src/services/familyService.ts—Participant_Start_Dateand donorSetup_Datewrites use MP-TZ wall-clock instead ofnew Date().toISOString().src/services/groupService.test.ts— mocksgetDomainInfo, resets both singletons, asserts MP-SQL format, and adds a 3-save round-trip regression proving no drift..claude/references/ministryplatform.datetimehandling.md— full reference (recipes, anti-patterns, Windows↔IANA table, testing guidance).CLAUDE.md— Key Development Practice chore(deps): security audit updates + mjml fix #12 + Reference Documents entry pointing to the new doc.Test plan
npx vitest run src/services/domainTimezoneService.test.ts— 16/16 passnpx vitest run(full suite) — 664/664 passTZ=UTC npx vitest run— 664/664 passTZ=America/Los_Angeles npx vitest run— 664/664 passnpm run lint— cleannpx tsc --noEmit— no new errors (pre-existing errors inhelper.test.ts,provider.test.ts,word-document.test.ts,logger.test.tsare untouched and unrelated)Start_Date = today, then re-save without changing fields, confirm date does not shift🤖 Generated with Claude Code