Fix datetime-local timezone shift by replacing Flatpickr with native picker#2581
Fix datetime-local timezone shift by replacing Flatpickr with native picker#2581mpscholten wants to merge 1 commit intomasterfrom
Conversation
…picker Remove Flatpickr for datetime-local inputs and use the native browser picker instead. Add JS to convert server-rendered UTC values to local time on page load, and convert back to UTC on form submit. This fixes the double timezone offset bug where Flatpickr's dateFormat: 'Z' mode misinterpreted datetime-local values (which have no Z suffix per HTML5 spec) as local times, causing the stored time to shift on every save. Fixes #2565 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Core Size & Compile Allocations Benchmark
HTTP Latency (GET /, 200 runs)
Top 10 modules (this PR)
|
|
I think I commented on that, but don't see this comment here for some reason. Let me try again. If we display local time to the users in datetime input fields, then we would also want to display local time everywhere else in UI. At least I do that in my app, and I use this helper in JS: function formatLocalISO(date) {
const pad = (n) => String(n).padStart(2, '0');
const year = date.getFullYear();
const month = pad(date.getMonth() + 1);
const day = pad(date.getDate());
const hours = pad(date.getHours());
const minutes = pad(date.getMinutes());
const seconds = pad(date.getSeconds());
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
function localizeTimes(root = document) {
root.querySelectorAll(".local-time").forEach(el => {
if (el.dataset.localized) return;
let timeStr = el.dataset.time;
timeStr = timeStr.replace(" UTC", "Z").replace(" ", "T");
const date = new Date(timeStr);
if (isNaN(date)) return; // safety guard
el.textContent = formatLocalISO(date);
el.dataset.localized = "true";
});
}and then this in Haskell code: renderTime :: UTCTime -> Html
renderTime time =
[hsx|
<span class="local-time" data-time={tshow time}></span>
|]How do you do this? Could this be supported by the framework itself? Can all these questions be solved in one place? |
|
I think this is mostly handled by Likely we need to support more customization of the output formatting |
|
Oh, good. I didn't notice them before. Then yes, just a param for the formatting for flexibility. That's a separate improvement then. |
Summary
datetime-localinputs, uses the native browser picker insteadinitDateTimeLocal()) to convert server-rendered UTC values to the user's local timezone on page loadFormDatareads the valuesinput[type='date']fields is unchangedRoot cause: PR #2491 changed
dateTimeFieldto renderUTCTimeasYYYY-MM-DDTHH:MM(no Z suffix) to match the HTML5datetime-localspec. Flatpickr'sdateFormat: 'Z'mode expects a Z-suffixed UTC string. Without it, Flatpickr interprets the UTC wall-clock time as local time, causing a timezone offset shift on every save. PR #2570 tried appending Z in JS, but the browser'sdatetime-localinput sanitization interferes, causing a double offset.This fix: Instead of fighting between the
datetime-localspec and Flatpickr's UTC mode, we remove Flatpickr for these inputs entirely. The native picker handles display, and simple JS Date math handles the UTC↔local conversion:value="12:00"el.value = "14:00"14:00in native picker12:0012:00Fixes #2565
Test plan
UTCTimedatetime field in a non-UTC timezone — verify the native picker shows local timeinput[type='date']fields still use Flatpickr🤖 Generated with Claude Code