While reworking the created calendar app-like thing,
I noticed that there was a gap when saving the time data sent by time_select
.
erb:new.html.erb(Excerpt only for time form)
<div class="start-date-input">
<div class="form-title">
Start time
<span class="indispensable">Mandatory</span>
</div>
<div class='input-date-wrap'>
<%= f.time_select(:start_time, {class:'select-date', id:"start-time", prompt:'--', time_separator: ':'}, ignore_data: true) %>
</div>
</div>
<div class="start-date-input">
<div class="form-title">
ending time
<span class="indispensable">Mandatory</span>
</div>
<div class='input-date-wrap'>
<%= f.time_select(:start_time, {class:'select-date', id:"start-time", prompt:'--', time_separator: ':'}, ignore_data: true) %>
</div>
</div>
Enter the date and time in the form as above and submit the data ...
ja.yml(l method+Time display has been set in the locale)
ja:
time:
formats:
default: "%Y/%m/%d %H:%M:%S"
short: "%H:%M"
erb:show.html.erb
<div class="event-info-left">
<p><%= event.day %></p>
<p><strong><%= l event.start_time, format: :short %></strong></p>
<p><strong>↓</strong></p>
<p><strong><%= l event.finish_time, format: :short %></strong></p>
</div>
!?!?!!!??!?!?
I should have entered it earlier at the start time 08:00 and the end time 09:00, but it is ** 19 minutes ** off. What happened ...
By the way, if you correct this time difference with the edit form ...
It will be fixed. Apparently there is something wrong with ** creating a new **.
First, check the parameters sent from the new form and the instance to be created.
When submitting a new form
[1] pry(#<EventsController>)> event_params
=> <ActionController::Parameters {
(Omission)
"day(1i)"=>"2021", "day(2i)"=>"1", "day(3i)"=>"1",
"start_time(1i)"=>"1", "start_time(2i)"=>"1", "start_time(3i)"=>"1", "start_time(4i)"=>"08", "start_time(5i)"=>"00",
"finish_time(1i)"=>"1", "finish_time(2i)"=>"1", "finish_time(3i)"=>"1", "finish_time(4i)"=>"09", "finish_time(5i)"=>"00",
} permitted: true>
[2] pry(#<EventsController>)> @event = Event.new(event_params)
(Omission)
day: Fri, 01 Jan 2021,
start_time: Mon, 01 Jan 0001 08:00:00 LMT +09:18,
finish_time: Mon, 01 Jan 0001 09:00:00 LMT +09:18,
The time is marked with ** "LMT" **. When I examined the ** "LMT" ** applied in the parameters, it was called ** "local time" **.
To find out the history of Japan Standard Time around 18 minutes 59 seconds Calendar Wiki/Japanese Prime Meridian Calendar Wiki/Local Time
In countries that are wide in the east and west, it may be more convenient to set a reference time for each city than to use standard time. ** The time corrected from standard time according to the difference in longitude is called local time **.
As you all know, the current standard time in Japan is based on 135 degrees east longitude in Akashi, Hyogo Prefecture, and the time difference is set at +09: 00 from Greenwich, England on the prime meridian. It was enacted at the 1884 International Meridian Conference and began to be used on January 1, 1888.
Until then, local time was set in each city, so ** Edo Tokyo local time ** was used as the standard for Japan. It is said that this ** local time in Tokyo was about +09: 19 from Greenwich **.
By the way, the time zone setting is described so that both the application itself and the database are JST as shown below.
application.rb
module TestApp
class Application < Rails::Application
config.load_defaults 6.0
config.time_zone = 'Asia/Tokyo'
config.i18n.default_locale = :ja
config.active_record.default_timezone = :local
(Omission)
end
end
Let's think about why LMT appears even if the time zone is set in JST.
The time type data also has the value of the date once as the specification of Active Record.
When submitting a new form
[1] pry(#<EventsController>)> event_params
=> <ActionController::Parameters {
(Omission)
"day(1i)"=>"2021", "day(2i)"=>"1", "day(3i)"=>"1",
"start_time(1i)"=>"1", "start_time(2i)"=>"1", "start_time(3i)"=>"1", "start_time(4i)"=>"08", "start_time(5i)"=>"00",
"finish_time(1i)"=>"1", "finish_time(2i)"=>"1", "finish_time(3i)"=>"1", "finish_time(4i)"=>"09", "finish_time(5i)"=>"00",
} permitted: true>
Even with the parameters sent from the new form (1i)… year (2i)… Month (3i)… Sun (4i)… time (5i)… minutes And so, the date is given along with each time.
In the newly created instance, check the date temporarily held by the time type. (Use the strftime method
for clarity)
Create an instance with the data submitted in the new form
[2] pry(#<EventsController>)> @event.start_time
=> Mon, 01 Jan 0001 08:00:00 LMT +09:18
[3] pry(#<EventsController>)> @event.start_time.strftime("%Y/%m/%d")
=> "0001/01/01"
This time, the time entered in the form is treated as the time ** "January 01, 0001 AD" **. Since this date is before 1888, it is probable that the LMT time has been applied.
If you try using the strftime method on the console
[3] pry(#<EventsController>)> @event.start_time
=> Mon, 01 Jan 0001 08:00:00 LMT +09:18
[4] pry(#<EventsController>)> @event.start_time.strftime("%H:%M")
=> "08:00"
[5] pry(#<EventsController>)>
It seems that the time is displayed here without any problem.
However, if you save this and look at the DB ...
You can see that it is saved at the time of the problem.
from here,
--Instance created based on parameters → LMT at 08:00
--When to save to database → Recalculate 08:00 in LMT to the database setting time zone (JST) and save
It is thought that it is moving.
You can see that this ** instance-> conversion at the data storage stage ** is causing this error. Since it was saved in the database with the time difference, the view also showed the time difference.
At the time of editing, we will also verify that it was possible to correct it according to the value of the form.
The data saved in the DB is pulled to the edit form. Check the data at the time of pulling.
Check the data brought from DB with edit
[1] pry(#<EventsController>)>
(Omission)
=> #<Event:0x00007fc64dfd9038
(Omission)
day: Fri, 01 Jan 2021,
start_time: Sat, 01 Jan 2000 07:41:01 JST +09:00,
finish_time: Sat, 01 Jan 2000 08:41:01 JST +09:00,
(Omission)
>
When it is newly created and saved in the DB, it is "JST" which is the converted LMT. The date at this time is ** January 01, 2000 **. (Probably the default value for JST) At this point, the date is after 1888, so it is thought that JST will handle it when it is saved in the DB again. It means that there was no deviation at the time of editing.
It turned out that the cause was ** "date at the time of new creation" **. To fix this old LMT, I would like to add some logic to the model so that each time can be given a date after the LMT before it can be sent to the database.
Define the method as set_time_zone
and
The value (day column) entered in the date form is also applied to the date of the time.
(Since it is a schedule app, it is assumed that dates before 1888 will not be handled.)
Then call this method with berofe_save
before saving the database.
event.rb
class Event < ApplicationRecord
before_save :set_time_zone
(Omission)
#Time zone measures at the time of new(Avoid time lag due to LMT)
def set_time_zone
year = self.day.year
month = self.day.month
day = self.day.day
self.start_time = self.start_time.change(year: year, month: month, day: day)
self.finish_time = self.finish_time.change(year: year, month: month, day: day)
end
end
After the correction, I tried to create a new one.
The time lag has been resolved and it has been saved safely! !!
I never thought I would look into astronomy or history in programming ... First of all, I am relieved to solve it within the year: sweat_smile:
It is difficult to find a similar case directly by searching ... I managed to arrive by logically thinking about what was the cause and where the error was caused. (It took a few days ...) It was an error that reminded me of the importance of thinking systematically.
Also, I would like to learn once again how to handle time zones and what kind of data is sent as parameters in the form.
This is a poor article for beginners, but I hope it will be of some help to you. Thank you for reading to the end.
Ruby 2.6.5 Rails 6.0.3.4 MySQL Visual Studio Code (GoogleChrome)
[Qiita] Set the date entered by default in Rails time_select to the input value of another field on the screen [Qiita] It seems that the date can be set even with time_select [TECH SCORE] Rails callback summary [Official] Rails documentation/time_select
To find out the history of Japan Standard Time around 18 minutes 59 seconds Calendar Wiki/Japanese Prime Meridian Calendar Wiki/Local Time
Recommended Posts