こんにちは
##エラーが出た背景
roo
を使ってexcelの日時のデータを取り込むよう開発を進めました。
ある程度できあがって確認しようとすると、下記のようなエラーが出ました。
おそらく, in_time_zone
メソッドがinteger型に対応できていないというエラーでないかと思いました。
下記に
- エラーメッセージが出た部分
- 対応するメソッド(controller)
- エラーが発生したファイル
を載せています。
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を書き換えました。
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
の記述をしています。
最後に
今回僕の初めての投稿なので至らない点があると思いますが、
僕なりに一生懸命頑張ったつもりです。笑
もし、何かアドバイスなどありましたらぜひ教えていただきたいです!