[RAILS] My 1880's ~ Fixed time zone from LMT to JST ~

Introduction/Situation when an error occurs

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>
form_image

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>
show_image

!?!?!!!??!?!?

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 ...

Consideration and verification of the cause

By the way, if you correct this time difference with the edit form ...

edit_show_image

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" **.

What is LMT

To find out the history of Japan Standard Time around 18 minutes 59 seconds Calendar Wiki/Japanese Prime Meridian Calendar Wiki/Local Time

LMT (Local Mean Time)… 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 **.

Why is it the LMT time?

Current time zone setting

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.

time type data also has a date

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.

At what timing does the time shift?

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 ...

db_image

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.

Why is there no deviation when editing?

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.

Measures/results

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.

edit_show_image edit_db_image

The time lag has been resolved and it has been saved safely! !!

At the end/impression

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.

Development environment

Ruby 2.6.5 Rails 6.0.3.4 MySQL Visual Studio Code (GoogleChrome)

Reference article

[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

My 1880's ~ Fixed time zone from LMT to JST ~
Convert from java UTC time to JST time
[Note] Download from S3, upload to S3
Memorandum Poem (updated from time to time)
[Reverse lookup] Spring Security (updated from time to time)
SpringBoot useful site collection (updated from time to time)
Touch all Spring "Guides" (updated from time to time)
Unify the Rails app time zone to Japan time