TimeWithZoneで時間操作に苦戦したこと

## はじめに
Railsアプリ作成時に`gem 'simple_calendar', '~> 2.0' 
`を使ったので、その際に困った`TimeWithZone`で時間操作する点について記載して行きたいと思います。


## バージョン
Rails 6.0.3
Ruby 2.6.6


## 参考資料
simple_calendar公式ドキュメント
https://github.com/excid3/simple_calendar
TimeWithZone　参考サイトです
https://api.rubyonrails.org/v6.0.2.1/classes/ActiveSupport/TimeWithZone.html
https://www.javadrive.jp/ruby/time_class/index2.html
## 作業内容

カレンダー作成は割愛させて頂きます！
最初のコードはこんな感じになります。
基本的なcrud処理

```ruby:app/controllers/events_controller.rb
class EventsController < ApplicationController

  def index
    @events = Event.all
  end

  def new
    @event = Event.new
  end

  def show
    @event = event.find(params[:id])
  end

  def create
    Event.create(event_params)
    redirect_to events_path
  end

  def destroy
    @event = event.find(params[:id])
    @event.destroy
    redirect_to events_path, notice:"削除しました"
  end

  def edit
    @event = Event.find(params[:id])
  end

  def update
    @event = Event.find(params[:id])
    if @event.update(event_params)
      redirect_to events_path, notice: "編集しました"
    else
      render 'edit'
    end
  end

  private

  def event_params
    params.require(:event).permit(:title, :content, :start_time)
  end

end
```


```erb:app/views/events/new.html.erb
<%= form_with(model: @blog, local: true) do |form| %>

  <div class="title">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

    <div class="time">
    <%= form.label :start_time %>
    <%= form.datetime_select :start_time %>
  </div>

  <div class="content">
    <%= form.label :content %>
    <%= form.text_field :content %>
  </div>


  <div class="submit">
    <%= form.submit %>
  </div>

<% end %>

```

viewに関してはform内が`タイトル・開始時刻・内容`と言う感じで
僕がしたい内容とは少し違っていました。

イベントカレンダーを作りたかったので、`日付+開始+終了時刻`を設けたいと考えました。



```:カラム追加
 end_time（終了時刻）
```
start_day(開始日時)も追加しようとしていたのですが、
データとして保持する際に``start_time``に日付の情報が入ってくるので省きます。

その代わりモデルに

```ruby:event.rb
attr_accessor :start_day　⇦記載

パラメーターとしてこの形で受け取れる
[2] pry(#<EventsController>)> @event.start_day
=> {1=>2021, 2=>7, 3=>22}
```




viewファイルも変更

```erb:app/views/events/new.html.erb
.
.
.
   <div class="form-group">↓追加
      <%= form.label :start_day, "時刻" %>
      <%= form.date_select :start_day, {discard_year: true}, class: "form-control" %><br>
    </div> 

    <div class="form-group">
      <%= form.time_select :start_time,  class: "form-control" %>
      ~　　　　　　　　　　　　　↓追加
      <%= form.time_select :end_time, class: "form-control" %>
    </div>
.
.
```

コントローラーでの処理も変更

```ruby:events_controller.rb

@event = Event.create(event_params)
このままだと対応できないので、

下記の処理に変更

@event = Event.new(event_params)
@event.start_time = ~~~~
@event.end_time = ~~~~
@event.save
```

`@event.start_time`で`開始時刻+作成日`が作れます
同じく`@event.end_time`で`終了時刻+作成日`が作成される。

`作成日`はタイムスタンプとして自動的に入ってしまう。

なので、入力欄に2月９日として投稿したとしても、、
2月３日（作成日）に追加されてしまう。

```ruby

pry(#<EventsController>)> @event.start_time
=> Wed, 03 Feb 2021 18:44:00 JST +09:00
```

そこで`@event.start_day`から[年][月][日]取得し上書きしてあげる。

```ruby
pry(#<EventsController>)> @event.start_day
=> {1=>2021, 2=>2, 3=>9}
　　　　[年]   [月]  [日]
```

なので、シンプルに記述

```ruby
@event.start_time = @event.start_day
```

```ruby
結果
1=>2021, 2=>2, 3=>9, 4=>0, 5=>0
   [年]   [月]  [日]    [時]    [分]
```

うん！今のままだと当然`[時][分]`が取得出来てない　笑




`@event.start_dayからは「年」「月」「日」`が取得。
`@event.start_timeからは「時間」「分」`が取得。
これを採用した新しいTimeWithZoneのインスタンスを作成して代入すれば解決します。

なので、
一旦この形にまとめます！

```ruby
Time.zone.local(2007, 2, 10, 15, 30, 45)        # => Sat, 10 Feb 2007 15:30:45 EST -05:00
```

安易な変数に変えておきます。

```ruby
    d = @event.start_day.values ⇦　値のみを取得したいのでvaluesメソッドを使っています！
    s = @event.start_time
    e = @event.end_time
```
```ruby
pry(#<EventsController>)> Time.zone.local(d[0], d[1], d[2], s.hour, s.min)
=> Tue, 09 Feb 2021 18:44:00 JST +09:00

```

うまく出来たのであとはこれを代入してあげれば完成！

```ruby
@event.start_time = Time.zone.local(d[0], d[1], d[2], s.hour, s.min)
@event.end_time = Time.zone.local(d[0], d[1], d[2], e.hour, e.min)
```

```ruby:app/controllers/events_controller.rb

class EventsController < ApplicationController

  def index
    @events = Event.all
  end

  def new
    @event = Event.new
  end

  def show
    @event = Event.find(params[:id])
  end

  def create
    @event = Event.new(event_params)
    d = @event.start_day.values
    s = @event.start_time
    e = @event.end_time
    @event.start_time = Time.zone.local(d[0], d[1], d[2], s.hour, s.min)
    @event.end_time = Time.zone.local(d[0], d[1], d[2], e.hour, e.min)
    if @event.save
      redirect_to events_path, notice: 'リストを作成しました'
    else
      flash.now[:alert] = "#{@event.errors.messages.length}つ空欄です。"
      render :new
    end
  end

  def destroy
    @event = Event.find(params[:id])
    @event.destroy
    redirect_to events_path, notice:"削除しました"
  end

  def edit
    @event = Event.find(params[:id])

  end

  def update
    @event = Event.find(params[:id])
    if @event.update(event_params)
      redirect_to events_path, notice: "編集しました"
    else
      render 'edit'
    end
  end

  private

  def event_params
    params.require(:event).permit(:title, :content, :start_time, :end_time, :start_day)
  end
end

```

## おわりに


`@event.start_day`から値を取り出すことにかなり苦戦しました^^;
いろんな変換メソッドを試したり、formヘルパーを触ってみたり
なかなか答えに辿りつきませんでした。
中身はハッシュで，欲しいのは「値」。`「ハッシュ」から「値」に変換する`だけの話でした。

何をしないといけないかをしっかり考えることが重要だと今回で改めて気付きました。^^