はじめに
仕事でコード書いていると、年に1回ぐらい日付関係の処理ではまるので、備忘録に記事を、まとめてました。
前提
DynamoDBを使用し、モデルは以下のように設定しています。
class Notification
include Dynamoid::Document
include Draper::Decoratable
table name: :notification, key: :notification_id
range :notified_at, :datetime
field :name, :string
private
def create_attrs(notification_id, name)
base = { id: id, notified_at: Time.zone.now, name: name }
end
end
まず、何にハマったかですが、notification_idとnotified_atでユニークな値を取得できる様にしたのですが、なぜか取得できない。。。
1つデータを作ったものとします。
Notification.find('1', range_key: Notification.last.notified_at)
=> #<Notification:0x00000040hogehoge>が取得できる
実際にブラウザ側からパラメーターを送って取得する場合
DateTime型で送られてもparamsで一旦文字列に変換され、datetimeに戻す必要があるので、下記の様に取得してみる
Notification.find('1', range_key: Notification.last.notified_at.to_s.to_datetime)
=> Dynamoid::Errors::RecordNotFound
なんで?!となった
結論
DiteTime型をStringに変換した際、ミリ秒部分がなくなり、再びDateTime型にしても、ミリ秒部分がなくなってしまうためであった。
説明
Notification.last.notified_at
=> Mon, 12 Dec 2022 07:38:49 +0000
Notification.last.notified_at.to_s.to_datetime
=> Mon, 12 Dec 2022 07:38:49 +0000
上記の様に見ると同じ値である様に見える。
しかし
Notification.last.notified_at == Notification.last.notified_at.to_s.to_datetime
=> false
これはDateTime型だと、ミリ秒までが表示されていないだけで、実際はミリ秒の値まであるため、falseとなっている。
この違いがTime型に変換してみるとよくわかった。
Notification.last.notified_at.to_time
=> 2022-12-12 07:38:49.997983757 +0000
Notification.last.notified_at.to_s.to_datetime.to_time
=> 2022-12-12 07:38:49 +0000
ではどうすれば、
Notification.last.notified_at
=> Mon, 12 Dec 2022 07:38:49 +0000
Notification.last.notified_at.iso8601(9).to_s.to_datetime
=> Mon, 12 Dec 2022 07:38:49 +0000
Notification.last.notified_at == Notification.last.notified_at.iso8601(9).to_s.to_datetime
=> true
Notification.find('1', range_key: Notification.last.notified_at.iso8601(9).to_s.to_datetime)
=> #<Notification:0x00000040hogehoge>
取得できました。
終わりに
今回、ハマってしまったポイントとしては、DateTime型では表示されないだけで、ミリ秒の値も持っているということを認識してなかった点にあったと思います。
私だけかもしれませんが、つい表示されないとないものと思い込んでしまうことがあるので、備忘録として記事を残したいと思いました。