こんにちは

エラーが出た背景

rooを使ってexcelの日時のデータを取り込むよう開発を進めました。
ある程度できあがって確認しようとすると、下記のようなエラーが出ました。
おそらく, in_time_zoneメソッドがinteger型に対応できていないと
下記に
- エラーメッセージが出た部分
- 対応するメソッド(controller)
- エラーが発生したファイル
を載せています。

Screen Shot 2021-03-22 at 1.02.11 PM.png

app/controller/ir/meeting_logs_controller.rb
  def time_from_excel_date_time(excel_date, excel_time)
    date = excel_date.in_time_zone

    if excel_time.is_a?(String)
      time = excel_time.to_time
      hour = time.hour
      minute = time.min
    elsif excel_time.is_a?(Integer)
      hour = (excel_time / 3600)
      minute = (excel_time % 3600 / 60)
    end

    date + hour.hour + minute.minute
  end

普段取り込むexcelファイル(該当箇所のみ)

id 日付 開始時間
12/9 1:00
12/8 1:00
11/27 1:00
11/26 1:00

今回エラーが発生したexcelファイル(該当箇所のみ)

id 日付 開始時間
12月9日 1:00
12月8日 1:00
11月27日 1:00
11月26日 1:00

原因

上の部分を見ていただければわかる通り、日付の区切られている部分が/月日かの違いによるものでした。
この部分が違うと、
/だとそのまま(String型)、
月日だと数字(Integer型)
が変数として取り込まれるので、String型にしか対応していなかったメソッドでエラーが発生してしまいました。

改善策

そのためcontrollerを書き換えました。

app/controller/ir/meeting_logs_controller.rb
  def time_from_excel_date_time(excel_date, excel_time)
  EXCEL_EPOCH = 2209078800
  TICKS_PER_DAY = 60 * 60 * 24
    if excel_date.is_a?(String) || excel_date.is_a?(Date)
      date = excel_date.in_time_zone
    elsif excel_date.is_a?(Integer)
      # 日付が漢字の場合、integer型で受け取る => 1899/12/31 からどれくらいの日数がたったかを表している
      # Unixのゼロタイム(基準)が "1970/1/1" に設定されている為、下記ステップで日付を求める
      # 1. TICKS_PER_DAY をかけて、1899/12/31 からどれくらいの秒数がたったかを計算
      # 2. 1から EXCEL_EPOCH 秒をを引き、1970/1/1 からどれくらいの秒数がたったかを計算

      unix_timestamp = excel_date * TICKS_PER_DAY - EXCEL_EPOCH
      date = Time.at(unix_timestamp).to_datetime - 8.hours - 1.day
    end

    if excel_time.is_a?(String)
      time = excel_time.to_time
      hour = time.hour
      minute = time.min
    elsif excel_time.is_a?(Integer)
      hour = (excel_time / 3600)
      minute = (excel_time % 3600 / 60)
    end

    date + hour.hour + minute.minute
  end

excelから取り込んだ日付の変数が入っているexcel_dateに対して、if文でString型とInteger型に分けて処理を走らせることにしました。
また、unix_timestampの部分が複雑なので下記に説明をしたいと思います。

unixとexcel

このコントローラーの記述は主にunixとexcelの基準の時間を合わせるために書きました。
コメントアウトでも書いてありますが、
excelは基準が1899/12/31なので帰ってくる変数は、1899/12/31から何日たっているかを表します。
しかし、Rubyに限らずunixを基準としているプログラミング言語は1970/1/1(ゼロタイム)を基準に作動します。
なので、excelの変数をunixの基準に合わせるために

unix_timestamp = excel_date * TICKS_PER_DAY - EXCEL_EPOCH

の記述をしています。

最後に

今回僕の初めての投稿なので至らない点があると思いますが、
僕なりに一生懸命頑張ったつもりです。笑
もし、何かアドバイスなどありましたらぜひ教えていただきたいです!