web-dev-qa-db-ja.com

RubyでのDateTimeのミリ秒の解像度

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を取得できますか?

26
SRobertJames

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

9
SRobertJames

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がオブジェクトに手を触れないようにするために、オブジェクトを手で押します。

19
mu is too short

私は、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 で見つけました。

これはこの問題の答えではないことを認識していますが、このノートが問題に苦しんでいる誰かの助けになることを願っています。

3
Joseph Lord

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が必要になる場合があります。

1
Chris Heald