30

2012-01-01T01:02:03.456ActiveRecordを使用してPostgresデータベースTIMESTAMPに保存しているような文字列があります。

残念ながら、Rubyはミリ秒を切り落とすようです。

ruby-1.9.3-rc1 :078 > '2012-12-31T01:01:01.232323+3'.to_datetime
 => Mon, 31 Dec 2012 01:01:01 +0300 

Postgrsはマイクロ秒の解像度をサポートしています。それに応じてタイムスタンプを保存するにはどうすればよいですか?少なくともミリ秒の解像度が必要です。

(PSはい、postgresでミリ秒の整数列をハックすることができます。そのようなものはActiveRecordの目的全体を打ち負かします。)

更新:
非常に役立つ応答は、RubyDateTimeがミリ秒単位で切り刻まれていないことを示していました。使用する#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を渡すのではなく、のNOW()関数を使用します)。created_at

これが私の最終的な質問につながります:
タイムスタンプフィールドでミリ秒の解像度を維持するためにActiveRecordを取得するにはどうすればよいですか?

4

4 に答える 4

23

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はおそらくActiveSupport::TimeWithZoneオブジェクトではなくDateTimeオブジェクトを提供しますが、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" 

connection_adapters/column.rbActiveRecordソースを見て、string_to_timeメソッドが何をするかを確認してください。あなたの文字列はfallback_string_to_timeパスをたどります、そしてそれは私が言うことができる限り近くの小数秒を保存します。Railsのソースで見た奇妙なこと、特にデータベース側のことを考えれば、他の場所で何か奇妙なことが起こっている可能性があります。ActiveRecordが文字列から手を離すように、文字列を手動でオブジェクトに変換してみます。

于 2013-01-01T02:14:17.870 に答える
9

理由はわかりませんが、問題m.happened_at = '2012-01-01T00:00:00.32323'.to_datetimeを解決するために上記のコードを変更します。m.happened_at = '2012-01-01T00:00:00.32323'

于 2013-01-01T10:34:03.307 に答える
3

私は、OS X(Mavericks)でRVMが提供するバイナリRuby 2.0.0-p247を使用していて、Postgresから時間を取得するときに秒の値全体に丸められていたときにここに行き着きました。Rubyを自分で再構築すると(rvm reinstall 2.0.0 --disable-binary)、問題が解決しました。

https://github.com/rails/rails/issues/12422で見つけたhttps://github.com/wayneeseguin/rvm/issues/2189を参照してください

これがこの問題の答えではないことを認識していますが、このメモが誰かがそれに苦労しているのに役立つことを願っています。

于 2013-11-07T09:35:33.823 に答える
1

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固有のモンキーパッチが必要になる場合があります。

于 2013-01-01T02:03:59.150 に答える