ActiveRecordを使用してPostgresデータベースのTIMESTAMPに格納している_2012-01-01T01:02:03.456
_のような文字列があります。
残念ながら、Rubyはミリ秒を刻むようです:
_Ruby-1.9.3-rc1 :078 > '2012-12-31T01:01:01.232323+3'.to_datetime
=> Mon, 31 Dec 2012 01:01:01 +0300
_
Postgrはマイクロ秒の解像度をサポートしています。タイムスタンプをそれに応じて保存するにはどうすればよいですか?少なくともミリ秒の解像度が必要です。
(PSはい、私はpostgresのミリ秒の整数列をハックする可能性があります。これは、ActiveRecordの目的全体を打ち負かします。)
更新:
非常に役立つ応答は、RubyのDateTime
が(ミリ秒)を切り刻んでいないことを示しました。 _#to_f
_を使用すると表示されます。しかし、次のようにします:
_m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime
m.save!
m.reload
m.happened_at.to_f
_
ミリ秒を落とします。
ここで興味深いのは、_created_at
_がRailsとPostgresの両方)でミリ秒を表示することです。しかし、他のタイムスタンプフィールド(上記の_happened_at
_など)は表示しません。 Railsは、DateTimeで渡すのではなく、_created_at
_に対してNOW()
関数を使用します)。
これは私の究極の質問につながります:
タイムスタンプフィールドのミリ秒の解像度を維持するために、どのようにしてActiveRecordを取得できますか?
上記のコードのm.happened_at = '2012-01-01T00:00:00.32323'.to_datetime
をm.happened_at = '2012-01-01T00:00:00.32323'
に変更すると問題が解決しますが、理由はわかりません。
ActiveRecordはデータベースの精度を完全に維持する必要があります。適切に調べているだけではありません。小数秒を確認するには、strftime
および%N
形式を使用します。たとえば、psql
は次のように言います。
=> select created_at from models where id = 1;
created_at
----------------------------
2012-02-07 07:36:20.949641
(1 row)
そしてActiveRecordはこれを言います:
> Model.find(1).created_at.strftime('%Y-%m-%d %H:%M:%S.%N')
=> "2012-02-07 07:36:20.949641000"
だからすべてがそこにあり、あなたはそれを見る方法を知る必要があるだけです。
また、ActiveRecordはおそらくDateTime
オブジェクトではなくActiveSupport::TimeWithZone
オブジェクトを提供しますが、DateTime
もすべてを保持することに注意してください。
> '2012-12-31T01:01:01.232323+3'.to_datetime.strftime('%Y-%m-%d %H:%M:%S.%N')
=> "2012-12-31 01:01:01.232323000"
ActiveRecordソースのconnection_adapters/column.rb
を見て、string_to_time
メソッドの機能を確認してください。あなたの文字列はfallback_string_to_time
パスをたどり、私が知る限り、秒の端数を維持します。 Railsのソース、特にデータベース側で見た奇妙なことを考えると、奇妙なことが他の場所で起こっている可能性があります。文字列を変換してみますActiveRecordがオブジェクトに手を触れないようにするために、オブジェクトを手で押します。
私は、RVMが提供するバイナリRuby 2.0.0-p247 on OS X(Mavericks))の使用に悩まされていたため、Postgresから時間を取得するときに秒の整数値に丸めていました。再構築Ruby自分(rvm reinstall 2.0.0 --disable-binary
)私のために問題を解決しました。
https://github.com/wayneeseguin/rvm/issues/2189 を参照してください https://github.com/Rails/rails/issues/12422 で見つけました。
これはこの問題の答えではないことを認識していますが、このノートが問題に苦しんでいる誰かの助けになることを願っています。
to_datetime
は、データのミリ秒の解像度を破壊しません-DateTime#to_s
は表示しません。
[1] pry(main)> '2012-12-31T01:01:01.232323+3'.to_datetime
=> Mon, 31 Dec 2012 01:01:01 +0300
[2] pry(main)> '2012-12-31T01:01:01.232323+3'.to_datetime.to_f
=> 1356904861.232323
そうは言っても、データを保持するときにActiveRecordが誤ってその情報を隠しているのではないかと思います。これはデータベースに依存しないため、すべてのデータベースターゲットで機能することが保証されているアプローチを取ります。 Postgresはタイムスタンプにマイクロ秒の情報を想定していましたが、MySQLはそうではないので、ARが最も低い共通値を選択するのではないかと思います。 ARの根本に入るまでは確信が持てませんでした。この動作を有効にするには、Postgres固有のmonkeypatchが必要になる場合があります。