Syntax Error.

[Sy] Amazon EMRでRubyのTime::to_dateメソッドは使えないので注意

2014/07/11

最近 AWSEMR(Elastic MapReduce) をHadoop streamingで使ってるんですが、Rubyのバージョンがどうやら1.8系らしく、Rubyを2.0系から始めたぼくが見事にハマったという話。

まず、何が起きたのか?

EMRで実行したいmapperをローカルで走らせたらうまくいくんですが、何故かEMR上ではコケる。

原因は?

mapperの中でタイムスタンプを年月日に変換する処理をこう書いてたんですね。

require 'date'
.
.
.
# 例えば、tm = Time.at(1405036212) みたいなTimeオブジェクト
dt = tm.to_date

ちなみにこの時ローカルのRubyのバージョンは2.1.1で、この場合だとdt = '2014-07-11'となります。

これをそのままEMRで動かそうとするとコケるわけですが、なんでも EMRのRubyのバージョンは1.8系らしく、1.8系では先ほどのTime::to_dateというメソッドがprivate だという罠。

なので、おとなしく以下のように書き直したらうまくいきました。

dt = tm.strftime('%Y-%m-%d')

・・・たぶん、昔からRubyやってる人はこんなミスはしないかと思いますが。そもそもEMRはなんでそんなに古いバージョンなのかと。

試しにローカルに1.8系を入れてテスト

試しに、以下のコードtest.rbを用意して、rbenvで2.1.1と1.8.7-p375の動きを比べてみます。

require 'date'

tm = Time.at(1405036212)
puts "strftime : #{tm.strftime('%Y-%m-%d')}"
puts "to_date  : #{tm.to_date}"

まずは2.1.1で実行。

$ /usr/local/var/rbenv/versions/2.1.1/bin/ruby test.rb
strftime : 2014-07-11
to_date  : 2014-07-11

問題なく、両方ともうまくいきました。

次に1.8.7-p375で実行。

strftime : 2014-07-11
test.rb:5: private method `to_date' called for Fri Jul 11 08:50:12 +0900 2014:Time (NoMethodError)

strftimeの方は問題ないですが、to_dateの方は「privateメソッドのto_dateが呼ばれたよ!」と狙い通りエラーになりました。

ひとこと

やっぱHadoop使うならJavaがいいのかな?