Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fixes Time objects to have same time as when saved in mongodb #455

Closed
wants to merge 5 commits into from

2 participants

@leifcr

New pull request because of incorrect pushes in the previous pull request.
One line for both REE and 1.9.3, instead of version dependent solution. Basically same as #443

@leifcr

Travis fails on compound keys. Time tests and extensions passes.

@cheald
Owner

iso8601 is ridiculously slow. Given that the core type conversions are core to read/write performance, I'd be really hesitant to endorse that solution.

Additionally, using #round explicitly breaks this test, which was added in response to a bugfix. If we're to preserve this test, then any millisecond-rounding feature must perform a floor rather than a round.

I'd propose just:

-          at(time.to_f).utc if time # ensure milliseconds are preserved with to_f (issue #308)
+          at((time.to_f * 1000.0).to_i / 1000.0).utc if time

This isn't as fast as #round, but it's cross-version compliant and doesn't break any tests.

@cheald cheald closed this pull request from a commit
@cheald cheald When performing Time#to_mongo, round times off to milliseconds and di…
…scard microseconds. Closes #455.
9b3bd27
@cheald cheald closed this in 9b3bd27
@leifcr

Sorry about not answering before. I agree that it is slow using iso8601...

I think the pull you just did is perfect, as 1.8.x is end of life.

Initial pull request was similar to your proposal, however, it was removed as it was not 1.8.x compatible.

Discussion here, about why it was changed.

Thanks for fixing this in master :+1:

I was about to go mongoid on a project, but now I got a reason to stick with MM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 16, 2012
  1. @leifcr

    Fixes time to round to 3 digits on float. (mongodb driver has same pr…

    leifcr authored
    …ecision). Makes comparing times possible before/after save. Still keeps milliseconds.
  2. @leifcr
Commits on Sep 7, 2012
  1. @leifcr
Commits on Sep 24, 2012
  1. @leifcr
  2. @leifcr
This page is out of date. Refresh to see the latest.
View
3  lib/mongo_mapper/extensions/time.rb
@@ -8,7 +8,7 @@ def to_mongo(value)
else
time_class = ::Time.try(:zone).present? ? ::Time.zone : ::Time
time = value.is_a?(::Time) ? value : time_class.parse(value.to_s)
- at(time.to_f).utc if time # ensure milliseconds are preserved with to_f (issue #308)
+ iso8601(time.utc.iso8601(3)).utc if time # keep time with milliseconds. (Same as BSON time)
end
end
@@ -19,6 +19,7 @@ def from_mongo(value)
value
end
end
+
end
end
end
View
27 test/functional/test_time.rb
@@ -0,0 +1,27 @@
+require 'test_helper'
+
+class TimeTest < Test::Unit::TestCase
+ context "time" do
+ setup do
+ @klass = Doc do
+ key :name, String
+ key :time, Time
+ end
+ end
+
+ should "have same time after building new document and saving document" do
+ doc = @klass.new(:name => "Bear", :time => Time.now.utc)
+ old_time = doc.time
+ doc.save
+ doc.time.to_f.should eql(old_time.to_f)
+ end
+
+ should "have same time after creating and reloading document" do
+ doc = @klass.create(:name => "Bear", :time => Time.now.utc)
+ old_time = doc.time
+ doc.reload
+ doc.time.to_f.should eql(old_time.to_f)
+ end
+
+ end
+end
View
28 test/functional/test_timestamps.rb
@@ -49,14 +49,36 @@ class TimestampsTest < Test::Unit::TestCase
doc = @klass.create(:first_name => 'John', :age => 27)
old_created_at = doc.created_at.to_f
- new_updated_at = Time.now + 5.seconds
+ if RUBY_VERSION < "1.9"
+ new_updated_at = Time.at(Float(((Time.now + 5.seconds).to_f*1000).to_i)/Float(1000))
+ else
+ new_updated_at = Time.at(Time.now + 5.seconds).round(3)
+ end
+
Timecop.freeze(new_updated_at) do
@klass.update(doc._id, { :first_name => 'Johnny' })
end
doc = doc.reload
- doc.created_at.to_f.should be_close(old_created_at, 0.001)
- doc.updated_at.to_f.should be_close(new_updated_at.to_f, 0.001)
+ doc.created_at.to_f.should eql(old_created_at)
+ doc.updated_at.to_f.should eql(new_updated_at.to_f)
+ end
+
+ should "not change update_at when callbacks are disabled" do
+ doc = @klass.create(:first_name => 'John', :age => 27)
+ old_created_at = doc.created_at
+ old_updated_at = doc.updated_at
+
+ @klass.skip_callback(:save, :before, :update_timestamps )
+ new_updated_at = Time.now + 1.seconds
+ Timecop.freeze(new_updated_at) do
+ @klass.update(doc._id, { :first_name => 'Bear' })
+ end
+ @klass.set_callback(:save, :before, :update_timestamps )
+
+ doc = doc.reload
+ doc.created_at.to_f.should eql(old_created_at.to_f)
+ doc.updated_at.to_f.should eql(old_updated_at.to_f)
end
end
end
View
8 test/unit/test_extensions.rb
@@ -282,7 +282,7 @@ class SupportTest < Test::Unit::TestCase
end
should "be time to milliseconds if string" do
- Time.to_mongo('2000-01-01 01:01:01.123456').to_f.should be_close(Time.local(2000, 1, 1, 1, 1, 1, 123456).utc.to_f, 0.0000001)
+ Time.to_mongo('2000-01-01 01:01:01.123456').to_f.should be_close(Time.local(2000, 1, 1, 1, 1, 1, 123456).utc.to_f, 0.001)
end
should "be time in utc if time" do
@@ -301,18 +301,18 @@ class SupportTest < Test::Unit::TestCase
context "Time.to_mongo with Time.zone" do
should "be time to milliseconds if time" do
Time.zone = 'Hawaii'
- Time.to_mongo(Time.zone.local(2009, 8, 15, 14, 0, 0, 123456)).to_f.should be_close(Time.utc(2009, 8, 16, 0, 0, 0, 123456).to_f, 0.0000001)
+ Time.to_mongo(Time.zone.local(2009, 8, 15, 14, 0, 0, 123456)).to_f.should be_close(Time.utc(2009, 8, 16, 0, 0, 0, 123456).to_f, 0.001)
Time.zone = nil
end
should "be time to milliseconds if string" do
Time.zone = 'Hawaii'
- Time.to_mongo('2009-08-15 14:00:00.123456').to_f.should be_close(Time.utc(2009, 8, 16, 0, 0, 0, 123456).to_f, 0.0000001)
+ Time.to_mongo('2009-08-15 14:00:00.123456').to_f.should be_close(Time.utc(2009, 8, 16, 0, 0, 0, 123456).to_f, 0.001)
Time.zone = nil
end
should "not round up times at the end of the month" do
- Time.to_mongo(Time.now.end_of_month).to_f.should be_close(Time.now.end_of_month.utc.to_f, 0.0000001)
+ Time.to_mongo(Time.now.end_of_month).to_f.should be_close(Time.now.end_of_month.utc.to_f, 0.001)
end
should "be nil if blank string" do
View
2  test/unit/test_time_zones.rb
@@ -11,7 +11,7 @@ class TimeZonesTest < Test::Unit::TestCase
should "preserve milliseconds" do
doc = @document.new(:created_at => '2011-02-12 16:01:02.543Z')
- doc.created_at.should be_close(Time.parse('2011-02-12 16:01:02.543Z'), 0.0000001)
+ doc.created_at.should be_close(Time.parse('2011-02-12 16:01:02.543Z'), 0.0001)
end
should "work without Time.zone" do
Something went wrong with that request. Please try again.