Datetime Picker Frequently Shows Incorrect Time for `Field::Time`
Created by: conradbeach
The Issue
Frequently, the datetime picker in Administrate displays the incorrect value in form fields displaying Field::Time
s.
This issue can be demonstrated in the example application by changing the type of the published_at
attribute in the PostDashboard
from published_at: Field::DateTime
to published_at: Field::Time
.
You can then observe the following behavior after creating a new Post
.
-
The value for
published_at
for thePost
is displayed as11:45AM
in both index and show views. -
When you click the edit button, you are taken to the edit form for the
Post
and thepublished_at
time is incorrectly displayed as20:45:00
. -
If you click save without making any modifications to the form, the
Post
is updated with the incorrectpublished_at
time. -
If you click the edit button again, the correct value for
published_at
is displayed in the form.
Different times behave differently. Some are displayed correctly, some are not.
This behavior is the same whether the database column is of type time
or datetime
.
I observed this behavior with and without timezones.
I haven't observed this behavior with Field::DateTime
s.
My Investigation & Analysis
Administrate makes use of the bootstrap-datetimepicker library to add a datepicker to datetime fields in forms. That library in turn depends on Moment.js for parsing dates and times. Administrate uses bootstrap-datetimepicker
via the datetime_picker_rails gem.
The file responsible for rendering Field::Time
form fields is app/views/fields/time/_form.html.erb
. It renders an <input type="text">
field. If you're editing an existing value, the partial doesn't use a valid datetime format for the value of that field though. It uses a datetime of the following format: 2000-01-01 20:45:00 UTC
(or perhaps 1999-12-31 17:45:00 -0800
if you're using timezones).
So you end up with a text input that looks like this:
<input data-type="time" type="text" value="2000-01-01 20:45:00 UTC" name="blog_post[published_at]" id="blog_post_published_at">
If you try to parse that datetime string using Moment.js, you get a warning along the lines of Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions.
So my first inclination was to think that properly formatting the datetime might fix the issue. This can be done pretty easily by changing a line in the app/views/fields/time/_form.html.erb
partial from:
<%= f.text_field field.attribute, data: { type: 'time' } %>
to:
<%= f.text_field field.attribute, data: { type: 'time' }, value: field.data.iso8601 %>
This results in a text field that looks like this:
<input data-type="time" value="2000-01-01T20:45:00Z" type="text" name="blog_post[published_at]" id="blog_post_published_at">
This, however, didn't fix the buggy behavior. Even with a valid ISO8601 datetime string, the form field still frequently shows the incorrect time.
If you disable JavaScript, the correct time is displayed in the form field. If you turn JS back on, the time is displayed incorrectly. This leads me to believe that bootstrap-datetimepicker
is parsing or rendering the time incorrectly. I don't think it's an issue within Administrate.
I'd like to submit a pull request to address this, but since datetime_picker_rails
is no longer maintained, I'm not sure if there's a way for me to do that.