Symptom Definition and Affected 8.1 Builds
The term here means this: an operator picks a calendar day in a Perspective DateTime Picker, and the value that gets displayed, stored, or passed to a query is the previous day. The defect is tracked by Inductive Automation as IGN-6087. Field reports place it on these builds:
| Ignition build | Field observation |
|---|---|
8.1.35 |
Day-behind selection present; no resolution found in release notes at that point |
8.1.44 |
Reproduced in a view with a coordinate root container; not reproduced in a freshly built view with a flex root container |
8.1.45 |
Reproduced in a quick bench test |
Two different faults produce the same symptom. The first is a timezone shift: the component produces the correct instant, and something downstream renders or reinterprets it in a zone west of where it was created. The second is component-internal: the picker's own display or emitted value is already wrong before any binding touches it. The fix differs, so separate them first.
Check 1: Put a Label next to the picker and bind it to the picker value, formatted to show date, time, and UTC offset. Select a known day. Expect: if the Label shows the selected day at 00:00 local, the component is correct and the fault is downstream (go to the value path audit). If the Label shows the previous day in the evening, continue with the timezone chain.
Timezone Chain Across Browser, Session, and Gateway
A date-only selection has no time of day, but every date value in Perspective is an instant: a count of milliseconds since the epoch. The component must pick a time to attach, and it attaches midnight. Midnight is only midnight in one timezone. The same instant, rendered in any zone west of the zone where it was created, falls on the previous calendar day.
Perspective carries three clocks in a single interaction:
- Browser zone: the client OS timezone, where the front end builds the date from the click.
- Session zone: the timezone the Perspective session reports and uses for formatting.
- Gateway zone: the JVM timezone on the server, used by gateway scripts, tag history, and named queries.
The hour you read is always 24 minus the absolute offset, which makes the offset diagnosable from a single reading.
Check 2: Read the time shown in the Check 1 Label and compute 24 minus that hour. Expect: the result equals the absolute UTC offset of the browser or session zone. A match proves a UTC-midnight versus local-render mismatch. Repeat from a client set to UTC; expect the day-behind error to disappear there, since the offset is zero.
Value Path Audit: Bindings, Strings, and Scripts
Most day-behind reports that survive Check 1 are caused by what happens to the value after the picker emits it. The recurring culprits:
| Value path | Mechanism | Correction |
|---|---|---|
Date written as an ISO date-only string, e.g. 2024-03-15
|
JavaScript parses date-only ISO strings as UTC midnight; date-time strings without an offset parse as local | Pass the instant (epoch ms or Date object), never a date-only string |
| Gateway script rebuilds the date from year/month/day | Gateway scripts run in the gateway JVM zone, not the client zone | Build calendar dates in the session zone, or pass the instant through untouched |
| SQL equality against midnight | Database column type and connection timezone shift midnight differently from the client | Query a half-open range: start of day inclusive, start of next day exclusive |
| Formatting transform with a hard-coded zone | Display zone disagrees with the zone that created the value | Format in the session zone |
Adding one day to compensate is wrong practice. It corrects clients west of UTC, breaks clients east of UTC, and fails around daylight-saving transitions.
Check 3: Trace the value from the picker to its final destination (tag, query parameter, dataset). At each hop, log the raw epoch milliseconds. Expect: the epoch value stays identical at every hop. Any hop where it changes by a whole-hour multiple is the point of reinterpretation.
View Root Container Isolation Test
If Check 1 shows the picker itself emitting or displaying the wrong day, the fault sits inside the component or its view. On an 8.1.44 gateway, a picker failed in a view whose root was a coordinate container, and a freshly built view with a flex root container, holding newly placed components, did not fail. That single observation does not prove the root container type is the cause, but it is a cheap, decisive isolation test.
- Create a new view with a flex root container.
- Drag a new DateTime Picker from the component palette. Do not copy and paste the existing one; pasting carries every property of the old instance, including any stale value or format settings.
- Configure only the properties the application needs.
- Open the new view in the same session, same browser, same client zone used in Check 1.
- Select the same test date.
If the fresh view is clean, rebuild the affected screen on a flex root, or place the new picker view as an embedded view inside the existing coordinate layout, then rerun the test in that embedded arrangement before rolling it out.
Check 4: Compare the old and new views side by side with the same date selected. Expect: the fresh view shows the selected day at 00:00 local. If both views fail identically, the root container is not the variable; keep the noon normalization below as the workaround and track IGN-6087 in the release notes.
Noon Normalization and Range Queries
For date-only use cases (shift reports, batch dates, production days), anchor the value at local noon instead of midnight. Apply it once, at the point where the picker value is first consumed:
# Pseudologic for a transform or change script on the picker value
selected = picker value (instant)
localParts = year, month, day of 'selected' evaluated in the SESSION time zone
normalized = instant for localParts at 12:00:00.000 in the SESSION time zone
write 'normalized' to the tag / query parameter / custom property
# Downstream query for 'that day'
WHERE ts >= start_of_day(normalized) AND ts < start_of_day(normalized) + 1 day
Evaluate year, month, and day in the session zone, not the gateway zone. Doing it in a gateway script without an explicit zone reintroduces the shift for any client whose zone differs from the server.
Check 5: Select a date and read the normalized value. Expect: the selected day at 12:00 local, and the same calendar day when formatted in the gateway zone.
End-to-End Verification
Before an upgrade or production rollout, search the Ignition release notes for IGN-6087 on the target build and run the full sequence below on that build, since the defect reproduced on 8.1.45 in a bench test.
- Check A, component output: Select a mid-month date. Expect: bound Label shows the selected day.
- Check B, month boundary: Select the 1st of a month. Expect: selected day, not the last day of the previous month.
- Check C, year boundary: Select January 1. Expect: January 1 of the selected year, not December 31.
- Check D, DST boundary: Select the day a local daylight-saving change occurs. Expect: correct calendar day.
- Check E, west-of-UTC client: Repeat A through D from a client at a negative UTC offset. Expect: identical calendar days.
- Check F, east-of-UTC client: Repeat A through D from a client at a positive UTC offset. Expect: identical calendar days.
- Check G, persistence: Read the stored value back from the tag or database into a fresh session. Expect: same calendar day, same epoch milliseconds as written.
FAQ
How do I tell if the Ignition date picker bug is a timezone issue?
Bind a Label to the picker value with date, time, and offset displayed. If it shows the previous day at an evening hour equal to 24 minus your UTC offset, the value is UTC midnight being rendered in local time.
Which Ignition versions have the DateTime Picker day-behind issue?
It is tracked as IGN-6087 and has been reported on 8.1.35, 8.1.44, and 8.1.45. Check the release notes for IGN-6087 on your target build and rerun the boundary-date tests before trusting any upgrade.
How do I stop a Perspective date from shifting a day when saved to SQL?
Normalize the picked date to 12:00 in the session zone before writing, and query with a half-open range from start of day to start of the next day. Never compare a column for equality with midnight.
How do I fix the date picker without rebuilding the whole view?
First test a freshly dragged picker in a new flex-root view; if it is clean, embed that view inside the existing layout. If it still fails, apply noon normalization on the value where it is first consumed.