web-dev-qa-db-fra.com

Résolution de milliseconde de DateTime In Ruby

J'ai une corde comme 2012-01-01T01:02:03.456 que je stocke dans un horodatage de base de données Postgres utilisant ActiveRecord.

Malheureusement, Ruby Semble couper les millisecondes:

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

Postgrs prend en charge la résolution microseconde. Comment puis-je obtenir mon horodatage pour être sauvé en conséquence? J'ai besoin d'au moins une résolution de milliseconde.

(PS Oui, je pouvais pirater une colonne entière millisecondes à Postgres; ce genre de défaite tout le but d'Activerecord.)

Mise à jour :
[.____] Les réponses très utiles ont montré que Ruby's DateTime est non couper les millisecondes; à l'aide de #to_f le montre. Mais faire:

m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime
m.save!
m.reload
m.happened_at.to_f

Fait tomber les millisecondes.

Maintenant, la chose intéressante est que created_at montre des millisecondes, à la fois en Rails et postgres. Mais d'autres champs horodatants (comme happened_at ci-dessus) ne le faites pas. (Peut-être Rails utilise une fonction NOW() pour created_at par opposition à passer dans une date d'heure).

Qui conduit à ma question ultime:
[.____] Comment puis-je obtenir ActiveRecord pour préserver la résolution de millisecond sur les champs d'horodatage?

26
SRobertJames

En changeant m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime Dans le code ci-dessus à m.happened_at = '2012-01-01T00:00:00.32323' résout le problème, même si je n'ai aucune idée de pourquoi.

9
SRobertJames

Activerecord devrait préserver la précision complète de la base de données, vous ne le regardez tout simplement pas correctement. Utilisez strftime et le %N format pour voir les secondes fractionnaires. Par exemple, psql dit ceci:

=> select created_at from models where id = 1;
         created_at         
----------------------------
 2012-02-07 07:36:20.949641
(1 row)

et Activerecord dit ceci:

> Model.find(1).created_at.strftime('%Y-%m-%d %H:%M:%S.%N')
 => "2012-02-07 07:36:20.949641000" 

Donc, tout est là, vous avez juste besoin de savoir comment le voir.

Notez également qu'Aciverecord vous donnera probablement ActiveSupport::TimeWithZone Objets plutôt que DateTime Objets mais DateTime conserve tout aussi:

> '2012-12-31T01:01:01.232323+3'.to_datetime.strftime('%Y-%m-%d %H:%M:%S.%N')
 => "2012-12-31 01:01:01.232323000" 

Jettes un coup d'oeil à connection_adapters/column.rb Dans la source d'Activerecord et vérifie ce que le string_to_time méthode fait. Votre chaîne descendrait le fallback_string_to_time chemin et qui conserve des secondes fractionnaires aussi près que je peux dire. Quelque chose d'étrange pourrait se passer ailleurs, je ne serais pas surpris de donner aux choses étranges que j'ai vues dans le Rails source, surtout le côté de la base de données. J'essayerais de convertir les cordes. Objets à la main pour que Activeiverecord empêche les mains.

19
mu is too short

Je me suis retrouvé ici lorsque je souffrais d'utiliser le RVM fournis par Binary Ruby 2.0.0-P247 sur OS X (Mavericks), ce qui provoque des valeurs entières de secondes lors de la récupération des temps de Postgres. Reconstruire Ruby moi-même (rvm reinstall 2.0.0 --disable-binary) a résolu le problème pour moi.

Voir https://github.com/wayneeseguin/rvm/issues/2189 que j'ai trouvé via https://github.com/rail/rails/issues/12422 .

Je reconnais que ce n'est pas la réponse à cette question, mais j'espère que cette note pourrait aider quelqu'un à lutter avec elle.

3
Joseph Lord

to_datetime ne détruit pas la résolution de la milliseconde des données - c'est simplement caché parce que DateTime#to_s ne l'affiche pas.

[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

Cela dit, je soupçonne que Activerecord cache par erreur cette information lorsqu'il persiste les données; N'oubliez pas que c'est la base de données-agnostique, il faut donc des approches garanties pour travailler sur toutes ses cibles de base de données. Bien que Postgres a supposé des informations microsecondes dans les horodatages, MySQL ne le fait pas, donc je soupçonne AR sélectionne pour le dénominateur commun le plus bas. Je ne pouvais pas être sûr sans entrer dans les tripes d'AR. Vous aurez peut-être besoin d'un soctureyPatch spécifique aux postgres pour permettre ce comportement.

1
Chris Heald