It looks as though if you ask a DateTime to add something to itself, it looks at the something, and if it''s an integer, it interprets it as a duration in seconds, but if it''s a Rational, it interprets it as a duration in days. It''s inconsistent. Why didn''t the designers settle on one type for durations and one way to interpret them? What should one store in a database for a duration? What rules should one follow to avoid being tripped up by numbers being interpreted as different measures depending on accidental features such as the numbers'' representations? This is very disappointing; engineering designs should make logical sense.>> x = DateTime.now=> Tue, 21 Dec 2010 12:10:14 -0500>> d1 = 1.second=> 1 second>> y = x + d1=> Tue, 21 Dec 2010 12:10:15 -0500>> y.class=> DateTime>> y - x=> Rational(1, 86400)>> d2 = y - x=> Rational(1, 86400)>> d1.class=> Fixnum>> d1=> 1 second>> 0 + d1=> 1>> d1 == d2=> false>> (x + d1) == (x + d2)=> true -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
On Dec 21, 5:17 pm, Jack Waugh <7aq3z2h...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> It looks as though if you ask a DateTime to add something to itself, > it looks at the something, and if it''s an integer, it interprets it as > a duration in seconds, but if it''s a Rational, it interprets it as a > duration in days.That''s not actually the whole store - If you did DateTime.now + 1 then you would get 1 day after now. The key is that 1.second (and similarly 3.days, 2.hours + 6.minutes etc) aren''t integers - they''re ActiveSupport::Duration objects. They quite often pretend to be integers (the number of seconds represented by the duration - although this is obviously dodgy if the duration is something like 1 month), largely because that''s quite convenient when dealing with Time objects and I suspect because of backwards compatibility (at one point in Rails'' history the .second/.day... methods were just convenience methods that returned the corresponding number of seconds)> > It''s inconsistent. Why didn''t the designers settle on one type for > durations and one way to interpret them? What should one store in a > database for a duration? What rules should one follow to avoid being > tripped up by numbers being interpreted as different measures > depending on accidental features such as the numbers'' > representations? This is very disappointing; engineering designs > should make logical sense.It depends on what the duration represents. Sometimes you really do just mean some fixed length of time, so storing a integer number of seconds is good enough. It''s often more complicated though, for example if a duration is 1 month then your users might expect the 3rd october to be followed by 3rd november and then by the 3rd of december even though those are actually different numbers of seconds. Similarly users will often expect that things that are 1 day long will end/start on the same time every day, even though when clocks go back/forward a day in local time is actually 23/25 hours long. Fred> > >> x = DateTime.now > > => Tue, 21 Dec 2010 12:10:14 -0500>> d1 = 1.second > => 1 second > >> y = x + d1 > > => Tue, 21 Dec 2010 12:10:15 -0500>> y.class > => DateTime > >> y - x > > => Rational(1, 86400)>> d2 = y - x > > => Rational(1, 86400)>> d1.class > => Fixnum > >> d1 > => 1 second > >> 0 + d1 > => 1 > >> d1 == d2 > => false > >> (x + d1) == (x + d2) > > => true-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Jack Waugh wrote in post #969867:> It looks as though if you ask a DateTime to add something to itself, > it looks at the something, and if it''s an integer, it interprets it as > a duration in seconds, but if it''s a Rational, it interprets it as a > duration in days. > > It''s inconsistent. Why didn''t the designers settle on one type for > durations and one way to interpret them?Adding a dimensionless number to a measurement with units is asking for trouble. Just specify units and you''ll be fine.> What should one store in a > database for a duration?Anything you like. Use composed_of if necessary.> What rules should one follow to avoid being > tripped up by numbers being interpreted as different measures > depending on accidental features such as the numbers'' > representations?Use units.> This is very disappointing; engineering designs > should make logical sense.It makes lots of sense to specify units (and as Fred said, 1.hour is a Duration, not a Fixnum). What doesn''t make sense is expecting the sum of a Time and a Fixnum to be anything but undefined. Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org Sent from my iPhone -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Frederick Cheung wrote in post #969871:> On Dec 21, 5:17pm, Jack Waugh <7aq3z2h...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> It looks as though if you ask a DateTime to add something to itself, >> it looks at the something, and if it''s an integer, it interprets it as >> a duration in seconds, but if it''s a Rational, it interprets it as a >> duration in days. > > That''s not actually the whole store - If you did DateTime.now + 1 then > you would get 1 day after now. > The key is that 1.second (and similarly 3.days, 2.hours + 6.minutes > etc) aren''t integers - they''re ActiveSupport::Duration objects. > They quite often pretend to be integers (the number of seconds > represented by the duration - although this is obviously dodgy if the > duration is something like 1 month), largely because that''s quite > convenient when dealing with Time objects and I suspect because of > backwards compatibility (at one point in Rails'' history > the .second/.day... methods were just convenience methods that > returned the corresponding number of seconds)I am actually curious how I could see from the object itself in a Rails context that it''s not "really" a Fixnum, but an ActiveSupport::Duration object $ rails c Loading development environment (Rails 3.0.3) 001:0> weekend = 2.days => 2 days 002:0> weekend.class => Fixnum # but there is more functionality than a "Fixnum" 003:0> weekend.singleton_class => #<Class:#<ActiveSupport::Duration:0xb727e068>> # a hint ? Also, here I did use specific units (in-casu "days"), but still I had naively expected a different result on line 005. 004:0> weekend.seconds => 172800 seconds # this is correct 005:0> weekend.days => 172800 days # I had expected ''2'' or ''2 days'' Thanks, Peter -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
"Just specify units and you''ll be fine." That appeals to my notion of what is logical. Let''s try it.>> x = DateTime.now=> Wed, 22 Dec 2010 01:30:36 -0500>> y = x + 1.day=> Thu, 23 Dec 2010 01:30:36 -0500 So far, so good.>> (y - x) / 1.second=> Rational(28799745541, 28800000000) Since y is one day later than x, y - x should be a day. Dividing that by 1 second should yield a pure number equal to the number of seconds in a day.>> ((y - x) / 1.second).to_i=> 0 Even if coerced to an integer, the number of seconds in a day should be much more than zero. I used units, but the result differs from what seems to me to make sense. How can I safely represent a duration in the database and then use the duration in date arithmetic? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
On Dec 21, 10:07 pm, Peter Vandenabeele <li...-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> wrote:> Frederick Cheung wrote in post #969871:> > I am actually curious how I could see from the object > itself in a Rails context that it''s not "really" a Fixnum, > but an ActiveSupport::Duration objectActiveSupport::Duration === foo would return true (or Fixnum === foo would return false)> Also, here I did use specific units (in-casu "days"), > but still I had naively expected a different result > on line 005. > > 004:0> weekend.seconds > => 172800 seconds # this is correct > 005:0> weekend.days > => 172800 days # I had expected ''2'' or ''2 days''a Duration object doesn''t have days (or seconds etc.) methods that return the invidual components (the parts method does that), so when you call days on it, it ends up calling days on its value in seconds.> > Thanks, > > Peter > > -- > Posted viahttp://www.ruby-forum.com/.-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
On Dec 22, 6:41 am, Jack Waugh <7aq3z2h...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> "Just specify units and you''ll be fine." > > That appeals to my notion of what is logical. Let''s try it. > > >> x = DateTime.now > > => Wed, 22 Dec 2010 01:30:36 -0500>> y = x + 1.day > > => Thu, 23 Dec 2010 01:30:36 -0500 > > So far, so good. > > >> (y - x) / 1.second > > => Rational(28799745541, 28800000000) > > Since y is one day later than x, y - x should be a day. Dividing that by 1 > second should yield a pure number equal to the number of seconds in a day. >The problem here is that y-x is a unitless number. Even if someone had thought to override / for datetime or durations (they haven''t) you can''t know that this is a number that has come from subtracting two datetimes, two dates, two times or something completely different> >> ((y - x) / 1.second).to_i > > => 0 > > Even if coerced to an integer, the number of seconds in a day should be much > more than zero. > > I used units, but the result differs from what seems to me to make sense. > How can I safely represent a duration in the database and then use the > duration in date arithmetic?When you subtract or divide datetime objects you get unitless Rationals - the rest of the code doesn''t know if that''s a number of seconds, days, years etc. ActiveSupport::Duration assumes seconds which happens to be wrong. If you used Time instead of DateTime I think things would work as you expect. If that''s not an option, I can''t think of a really nice way of handling this short of adding quite a lot of extra stuff to DateTime / wrapping DateTime in something else or just being really meticulous about always being very aware that some numbers are numbers of days and others numbers of seconds. Even then I think you could always find some operation (squareroot, gamma function, whatever) that exposed that something was thinking in days and the other was thinking in seconds. Fred -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Frederick Cheung wrote in post #970028:> On Dec 22, 6:41am, Jack Waugh <7aq3z2h...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> So far, so good. >> >> >> (y - x) / 1.second >> >> => Rational(28799745541, 28800000000) >> >> Since y is one day later than x, y - x should be a day. Dividing that by 1 >> second should yield a pure number equal to the number of seconds in a day. >> > The problem here is that y-x is a unitless number.Well, then *there''s* the bad design decision. DateTime - DateTime should return a Duration, not a Fixnum. Hmm. Perhaps I''ll submit a core patch for this. Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org Sent from my iPhone -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Frederick Cheung wrote in post #970025:> a Duration object doesn''t have days (or seconds etc.) methods that > return the invidual components (the parts method does that)Many thanks. I found that very useful to understand the behaviour. $ rails c Loading development environment (Rails 3.0.3) 001:0> a_long_time = 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds => 1 year, 2 months, 25 days, and 18367 seconds 002:0> a_long_time.parts => [[:years, 1], [:months, 2], [:days, 21], [:days, 4], [:seconds, 18000], [:seconds, 360], [:seconds, 7]] Peter -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
On Dec 22, 12:09 pm, Marnen Laibow-Koser <li...-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> wrote:> Frederick Cheung wrote in post #970028: > > > On Dec 22, 6:41am, Jack Waugh <7aq3z2h...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > >> So far, so good. > > >> >> (y - x) / 1.second > > >> => Rational(28799745541, 28800000000)There''s one gotcha here: the ''+ 1.day'' part appears to drop the microseconds part of the DateTime. For instance, this will show the same sort of behavior:>> d = DateTime.now >> (d - Time.parse(d.inspect).to_datetime)*86400 # => a number smaller than one; actually the undisplayed fractional secondsHere the Time.parse chunk basically zeroes out everything but the displayed parts of d, causing the difference. If I repeat your test with this change:>> x = DateTime.now=> Wed, 22 Dec 2010 16:11:47 -0500>> x_flat = Time.parse(x.inspect).to_datetime=> Wed, 22 Dec 2010 16:11:47 -0500>> y = x_flat + 1.day=> Thu, 23 Dec 2010 16:11:47 -0500>> y - x_flat=> Rational(1, 1) Which matches the definition of DateTime#-, returning a result in days. As to the division issue, I don''t think that''s the intended reading of .days and friends. It *used* to be (back when 1.day => 86400), but that hasn''t been the behavior since 2007 in: https://github.com/rails/rails/blob/276c9f29cde80fafa23814b0039f67504255e0fd/activesupport/lib/active_support/duration.rb (would link to the old Trac ticket, but dev.rubyonrails.org seems to be down). The ActiveSupport::Duration class was explicitly designed to make + and - work correctly (corresponding to passing the given number and unit to DateTime#adjust), not to do any other unit-related conversions. If you want the old behavior, you can call .to_i on a Duration:>> 1.day.to_i# => 86400 --Matt Jones -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.