開発
Aws::Recordのdatetime_attrでタイムゾーンを保持する方法
shimizu
こんにちは。今回は、Aws::Recordでの日時型属性の値に、タイムゾーンを持たせる方法についてご紹介します。
AWSのDynamoDBをRubyで活用するためのgemであるAws::Recordは、DynamoDB上のテーブルをRubyオブジェクトにマッピングして扱えるという大変便利なライブラリーです。O/Rマッパーとして機能し、MySQLをActiveRecordで読み書きするような感覚で使うことができます。
例えば、テーブルの構造に合わせて以下のようにプロパティーを定義すると、モデルクラスが作成されます。
class MyModel include Aws::Record string_attr :name, hash_key: true integer_attr :post_id boolean_attr :is_active datetime_attr :created_at end
ここで一つ落とし穴があります。このプロパティーを見てください。
datetime_attr :created_at
ご推察の通り、これは日時型の属性を表します。ということで、何気なく日時を代入して保存してから再度読み込んでみます。
item = MyModel.new( name: "item01", created_at: Time.zone.local(2018, 3, 12, 9, 0) ) p item.created_at #=> "2018-03-12T09:00:00+09:00" item.save! item = MyModel.find(name: "item01") p item.created_at #=> "2018-03-12T00:00:00+00:00"
おや、午前9時として保存したはずが、読み込み直すと時刻が午前0時になってしまいました。よく見るとタイムゾーンが「+09:00」(JST)から「+00:00」(UTC)に変わっています。指している時刻は保存の前後で同一ですが、指定したローカルタイムゾーンに関係なくUTCの値で保存されてしまうようです。ちょっと直感的ではないですね。
この挙動を修正するには、プロパティー定義の際にオプションとして「use_local_time: true」を指定します。
class MyModel include Aws::Record string_attr :name, hash_key: true integer_attr :post_id boolean_attr :is_active datetime_attr :created_at, use_local_time: true end
こうすることで、指定したタイムゾーンを保持したまま値を保存することができます。
このオプション、記事公開時点では公式のドキュメントに記載がなく、ハマりやすそうなポイントです。実際の開発作業において問題となりました(汗)。いろいろ解決方法を探る中、ライブラリの内部処理用クラスの項目に載っているソースコードにそれとなく記述があることから判明しました。ご参考になれば幸いです!