Ruby on Rails中DateTime过滤器单文本字段时区转换问题咨询
Hey there! Let's tackle your two issues step by step—first that annoying UTC value flash in your single text field, then the validity of moment.tz.guess() in production.
1. Fixing the UTC Value Flash Problem
The root cause here is that you're directly modifying the text field's value to the UTC timestamp when the button is clicked, then the page reloads and resets it back to the user's input. That split-second change causes the flash.
Instead of altering the visible input, we can handle the timezone conversion behind the scenes when the form submits, keeping the user's input displayed the whole time. Here are two solid approaches:
Option 1: Use a Hidden Field (Simpler)
Keep your single visible text field for user input, but add a hidden field to send the converted UTC value to the backend:
.form-group = f.label :from_time, "From", class: 'sr-only' # Visible input for user's raw date/time = text_field_tag :from_time_display, @booking_filter_form.from_time, placeholder: 'From time', class: 'form-control', id: "from_time_id", onkeydown: "event.preventDefault()" # Hidden field to hold converted UTC value = f.hidden_field :from_time, id: "hidden_from_time"
Then update your JavaScript to intercept the form submit event (instead of button click) and populate the hidden field:
// Replace 'your_form_selector' with your actual form ID/class $('your_form_selector').on('submit', function(event) { const userInput = $("#from_time_id").val(); if (userInput) { const utcTime = time_conversion(userInput); $("#hidden_from_time").val(utcTime); } else { $("#hidden_from_time").val(""); } // Let the form submit normally—no need to prevent default here });
Option 2: Modify FormData Directly (No Hidden Field)
If you don't want to add a hidden field, you can manipulate the form data before it's sent:
$('your_form_selector').on('submit', function(event) { const form = this; const formData = new FormData(form); const userInput = $("#from_time_id").val(); if (userInput) { const utcTime = time_conversion(userInput); // Remove the raw user input field if we don't need to send it formData.delete('filter_forms_booking[from_time_display]'); // Add the converted UTC value formData.append('filter_forms_booking[from_time]', utcTime); } else { formData.append('filter_forms_booking[from_time]', ''); } // Submit the modified form data via AJAX to avoid full page reload (optional but smoother) $.ajax({ url: form.action, method: form.method, data: formData, processData: false, contentType: false, success: function(response) { // Update your page content with the response $('#your_content_container').html(response); // Ensure the visible input stays as the user's original input $("#from_time_id").val(userInput); } }); event.preventDefault(); // Stop the default form submit since we're using AJAX });
Both approaches keep the visible input showing the user's original value, eliminating the flash entirely.
2. Moment.tz.guess() in Production
Good news—moment.tz.guess() works reliably in production for most modern browsers. Here's what you need to know:
- It relies on the browser's
Intl.DateTimeFormatAPI, which is supported by all modern browsers (Chrome, Firefox, Safari, Edge) and even IE11+. - For extremely old browsers (like IE10 and below), it might fall back to guessing based on the browser's locale settings, which could be less accurate. If you need to support these, add a fallback:
let zone = moment.tz.guess(); // Fallback to UTC if guess fails if (!zone) { zone = 'UTC'; } - A quick heads-up: Moment.js is officially deprecated. If you're starting a new feature or refactoring soon, consider switching to Luxon (the recommended replacement from the Moment team). Luxon uses native browser APIs for timezone handling, which is more efficient and future-proof.
内容的提问来源于stack exchange,提问作者Muhamadhurabik A

