@nsshunt/stsfhirpg
v1.2.50
Published
STS FHIR Postgres (pg) Persistence
Readme
stsfhirpg
Some notes on current date/time testing stuff
Yes — these three are timezone bugs, and the diffs show two different timezone-sensitive code patterns.
For the first and third failures, the shift is exactly Brisbane (+10) versus GitHub UTC:
Local expected:
2025-06-30T14:00:00.000Z
+10 hours
= 2025-07-01 00:00 Brisbane
GitHub:
2025-07-01T00:00:00.000ZSame for the birthdate:
Local: 1974-12-24T14:00:00.000Z
GitHub: 1974-12-25T00:00:00.000ZThat almost certainly means somewhere you're doing something equivalent to:
new Date(year, month, day);because that constructor means midnight in the machine's local timezone.
On your machine:
TZ = Australia/BrisbaneOn GitHub:
TZ = UTCso you get different instants.
The second failure is even more revealing:
SP_VALUE_LOW
local: 2025-09-18T21:00:00.000Z
CI: 2025-09-18T21:00:00.000ZThe underlying instant is identical.
But:
local SP_STR: 20250919
CI SP_STR: 20250918That tells me you're almost certainly taking that Date and doing something like:
date.getFullYear();
date.getMonth();
date.getDate();Those are local-time getters.
At:
2025-09-18T21:00:00ZBrisbane sees:
2025-09-19 07:00while GitHub UTC sees:
2025-09-18 21:00Hence:
Brisbane -> 20250919
GitHub -> 20250918So that's definitive.
Immediate way to prove it
Add this temporarily to your GitHub test job:
env:
TZ: Australia/BrisbaneFor example:
jobs:
test:
runs-on: ubuntu-latest
env:
TZ: Australia/Brisbane
steps:
- uses: actions/checkout@v4
# ...
- run: yarn testI expect your remaining three tests will pass.
But I would use that only as confirmation, not the permanent fix.
The real fix
FHIR date specifically has no timezone — it represents a calendar date such as 1974-12-25, not an instant in Brisbane, UTC, New York, etc. (HL7)
So your parser should ideally be deterministic regardless of:
developer machine
GitHub runner
Docker
Kubernetes
production serverIf you're converting a FHIR date to a range of instants for database searching, I'd define the range in UTC explicitly.
Instead of:
const low = new Date(year, month - 1, day);use:
const low = new Date(Date.UTC(year, month - 1, day, 0, 0, 0, 0));and:
const high = new Date(Date.UTC(year, month - 1, day, 23, 59, 59, 999));Then everywhere you extract components from a Date, don't mix in local getters.
Instead of:
date.getFullYear();
date.getMonth();
date.getDate();use:
date.getUTCFullYear();
date.getUTCMonth();
date.getUTCDate();For example:
function dateOrdinal(date: Date): number {
const year = date.getUTCFullYear();
const month = date.getUTCMonth() + 1;
const day = date.getUTCDate();
return year * 10000 + month * 100 + day;
}Then:
2025-09-18T21:00:00Zwill always become:
20250918regardless of where the application runs.
However, there's one important semantic question in your second test. Your expected value is:
SP_STR = 20250919
SP_VALUE = 2025-09-18T21:00:00ZThat suggests the original FHIR value probably carried an offset such that the intended calendar date was September 19 even though its UTC instant is September 18.
If so, simply switching everything to getUTCDate() could be wrong for that particular dateTime case.
For FHIR dateTime, when a time is supplied the timezone is significant. (HL7) So ideally:
FHIR date
-> preserve calendar components directly
FHIR dateTime
-> preserve supplied timezone/calendar meaning
AND calculate UTC instant separatelyIn other words, avoid this general pattern:
string
↓
Date
↓
extract year/month/day againbecause Date throws away the distinction between the original textual timezone and the runtime machine timezone.
A safer model is:
Original:
2025-09-19T00:00:00+03:00
Calendar date:
20250919
Instant:
2025-09-18T21:00:00ZThose are both correct, and one shouldn't be reconstructed from the other using the server's timezone.
So I'd first set:
TZ: Australia/Brisbaneto prove the diagnosis. Then paste your date parsing function — particularly where you calculate SP_STR, SP_VALUE_LOW/HIGH, and the ordinal — and I can show you exactly which Date calls are environment-dependent and how I'd make the FHIR date handling deterministic.
