Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Preserve millisecond values on times [Fixes #308] #390

Merged
merged 1 commit into from

3 participants

Kevin Shekleton Brandon Keepers John Nunemaker
Kevin Shekleton

I've taken a stab at ensuring millisecond values are preserved on times. Thanks for looking at this and let me how this looks.

Brandon Keepers

@kpshek thanks for the pull request.

@jnunemaker do you remember the original issue with this?

John Nunemaker
Owner
Kevin Shekleton

I went back through the commit history here on Github and found that originally, times were stored to millisecond precision (which is what BSON allows).

https://github.com/jnunemaker/mongomapper/blob/c22bbde4fa1cfbc310d79cb0e50203310ffb03d1/lib/mongo_mapper/support.rb#L183-184

However, note in this version the milliseconds were calculated using floating point arithmetic and rounding which will produce slightly different values than what was intended.

...which was then followed up in commit ad25155 where milliseconds were removed.

The commit messages indicates milliseconds were removed due to the aforementioned rounding issues and @jnunemaker not seeing a need to use millisecond precision for representing times in Mongo.

I have an application in which I'm dealing with date/times in which millisecond precision is crucial and thus have a need to store this level of precision in my time attributes. I'm guessing the commenter on commit ad25155 and the person who logged issue #308 are in similar situations. Additionally, Mongo itself supports millisecond precision.

John Nunemaker
Owner
Kevin Shekleton

Thanks for the information on a short term solution - I can easily use that in the interim.

Out of curiosity, do you have plans to incorporate the proposed pull request changes into master? Thanks again for being so responsive and looking into this with me.

John Nunemaker
Owner

I'm definitely not opposed to supporting it if mongo supports it. I guess my only question is backwards compatibility. I suppose we could just create a TimeWithoutMilliseconds type and recommend people change times to that when upgrading.

@bkeepers any thoughts?

Brandon Keepers

I'm good with it. I can't really think of any compatibility issues.

John Nunemaker
Owner
Kevin Shekleton

@jnunemaker Sounds good. Let me know how the tests against Harmony go or if you'd like another type.

Kevin Shekleton

@jnunemaker - have you had a chance to run your tests against Harmony yet?

John Nunemaker
Owner
Brandon Keepers bkeepers merged commit 029dd45 into from
Brandon Keepers

Tests pass on harmony. Thanks for the pull request!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
3  lib/mongo_mapper/extensions/time.rb
View
@@ -8,8 +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)
- # strip milliseconds as Ruby does micro and bson does milli and rounding rounded wrong
- at(time.to_i).utc if time
+ at(time.to_f).utc if time # ensure milliseconds are preserved with to_f (issue #308)
end
end
10 test/functional/test_timestamps.rb
View
@@ -47,16 +47,16 @@ class TimestampsTest < Test::Unit::TestCase
should "set updated_at on document update but leave created_at alone" do
doc = @klass.create(:first_name => 'John', :age => 27)
- old_created_at = doc.created_at
- old_updated_at = doc.updated_at
+ old_created_at = doc.created_at.to_f
- Timecop.freeze(Time.now + 5.seconds) do
+ new_updated_at = Time.now + 5.seconds
+ Timecop.freeze(new_updated_at) do
@klass.update(doc._id, { :first_name => 'Johnny' })
end
doc = doc.reload
- doc.created_at.should == old_created_at
- doc.updated_at.should_not == old_updated_at
+ 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)
end
end
end
8 test/unit/test_extensions.rb
View
@@ -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 == Time.local(2000, 1, 1, 1, 1, 1, 0).utc.to_f
+ 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)
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 == Time.utc(2009, 8, 16, 0, 0, 0, 0).to_f
+ 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.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 == Time.utc(2009, 8, 16, 0, 0, 0, 0).to_f
+ 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.zone = nil
end
should "not round up times at the end of the month" do
- Time.to_mongo(Time.now.end_of_month).to_i.should == Time.now.end_of_month.utc.to_i
+ Time.to_mongo(Time.now.end_of_month).to_f.should be_close(Time.now.end_of_month.utc.to_f, 0.0000001)
end
should "be nil if blank string" do
5 test/unit/test_time_zones.rb
View
@@ -9,6 +9,11 @@ class TimeZonesTest < Test::Unit::TestCase
end
end
+ 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)
+ end
+
should "work without Time.zone" do
Time.zone = nil
Something went wrong with that request. Please try again.