はじめに/問題発生時の状況

開発環境

Ruby 2.6.5
Rails 6.0.3.4
MySQL
Visual Studio Code
(GoogleChrome)

カレンダーアプリ的なものを作成中です。
日付と開始・終了時間をそれぞれ分けてDBへ保存したいので、時間についてはtime型カラムで、time_selectを使用してフォームを作成しました。

new.html.erb(時間フォーム分のみ抜粋)
<div class="start-date-input">
  <div class="form-title">
    開始時間
    <span class="indispensable">必須</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">
    終了時間
    <span class="indispensable">必須</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

上記のように日付と時間をそれぞれフォームへ入力して、試しにデータを送信すると、

db

日時・各時間共にそれぞれ無事にDBへ保存されている様子です。
ではビューへ表示しようと取得すると…

show.html.erb
<div class="event-show-info-left">
  <p><%= @event.day %></p>
  <p><strong><%= @event.start_time %></strong></p>
  <p><strong>↓</strong></p>
  <p><strong><%= @event.finish_time %></strong></p>
</div>

before

!!!?!!!?

時間にそれぞれ、謎の年月も一緒に表示されております…
20世紀なこの子は一体何者…

原因の考察・検証

一度、送信データのparamsを確認しました。

[1] pry(#<EventsController>)> params
=> <ActionController::Parameters {
(省略)

 "day(1i)"=>"2020", "day(2i)"=>"12", "day(3i)"=>"2", 
"start_time(1i)"=>"1", "start_time(2i)"=>"1", "start_time(3i)"=>"1", "start_time(4i)"=>"10", "start_time(5i)"=>"00", 
"finish_time(1i)"=>"1", "finish_time(2i)"=>"1", "finish_time(3i)"=>"1", "finish_time(4i)"=>"13", "finish_time(5i)"=>"30", 

(省略)
} permitted: false>

(1i)…年
(2i)…月
(3i)…日
(4i)…時
(5i)…分
というように、各時間と共に年月日も付与されていることが分かります。

時間を保存するのでtime型にしたので、DBには反映されませんが、
time_selectの仕様としては年月日に"1"もつけて扱われる、というように考えられます。
この"1"というのがそのままビューに取得され、例の2000-01-01の原因なようです。

〜では、時間だけを取得するにはどうするか…?〜

ビュー側に何か一工夫したいところです。
調べたところ…

【公式】Ruby 2.7.0 リファレンスマニュアル instance method Time#strftime

strftime(format) -> String
時刻を format 文字列に従って文字列に変換した結果を返します。

上記を参考に、strftimeが活躍しそうです!
開始時間・終了時間クラスに対してstrftimeを使用し、文字列にフォーマットします。

結果

時間のみを取得するので、フォーマットは下記を使います。

  • %H: 24時間制の時(00-23)
  • %M: 分(00-59)

先ほどのビューファイルに、.strftime("%H:%M")を付け加えました。

show.html.erb(修正)
<div class="event-show-info-left">
  <p><%= @event.day %></p>
  <p><strong><%= @event.start_time.strftime( "%H:%M" ) %></strong></p>
  <p><strong>↓</strong></p>
  <p><strong><%= @event.finish_time.strftime( "%H:%M" ) %></strong></p>
</div>

after

時間のみ表示が出来ました!!

終わりに/感想

strftimetime_selectは名コンビでした!

時間の扱いについては今後、規模の大きな実装をするようになると
タイムゾーンや閏年などの特殊な配慮が必要になってくるとも感じました。
これを機に、Timeクラス系クラスの理解も深めたいと思います。

初学者で拙い記事ですが、少しでもお役に立てると嬉しく思います。
最後まで読んでいただき、誠にありがとうございました。

追記

11/11 21:40
日時のフォーマットについてはDRYの面から、タイムゾーンとロケール設定、lメソッドで対応するのが良いとご指導いただきました。
下記の記事をご参照ください。

【初心者向け・動画付き】Railsで日時をフォーマットするときはstrftimeよりも、lメソッドを使おう

@jnchito 様 ありがとうございました!

参考記事

【公式】Ruby 2.7.0 リファレンスマニュアル instance method Time#strftime

【公式】Ruby on Rails 6.0.3.4 Module ActionView::Helpers::DateHelper

【Qiita】strftimeとは?

【Qiita】Time型のデータの値を、時刻部分だけ表示する

【Hatena Blog】time_selectで時間だけを入力させる[rails]