0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rooで取り込んだExcelの日時のデータがうまく反映されない

Last updated at Posted at 2021-03-25

こんにちは
##エラーが出た背景
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

の記述をしています。

最後に

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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?