Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails on date object values returned by date.end_of_day.to_datetime and date.to_datetime.end_of_day when compared returns false

ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]

Rails 3.0.20

Recently why working on a project on RSpecs related to DateTime on Rails I found out that on a given date the values emitted by following statements

    date.end_of_day.to_datetime

and

    date.to_datetime.end_of_day

when compared returned false though they represented identical date-time.

To confirm this I opened up Rails console and tried out following

  1.9.3dev :053 > monday = Time.now.monday
   => 2013-02-25 00:00:00 +0530

  1.9.3dev :054 > monday.class
   => Time

  1.9.3dev :055 > d1 = monday + 1.hour
   => 2013-02-25 01:00:00 +0530

  1.9.3dev :056 > d2 = monday + 1.hour
   => 2013-02-25 01:00:00 +0530

  1.9.3dev :058 > d1_eod_datetime = d1.end_of_day.to_datetime
   => Mon, 25 Feb 2013 23:59:59 +0530

  1.9.3dev :059 > d2_eod_datetime = d2.to_datetime.end_of_day
   => Mon, 25 Feb 2013 23:59:59 +0530

  1.9.3dev :061 > d1_eod_datetime == d2_eod_datetime
   => false

  1.9.3dev :062 > d3_eod_datetime = d2.to_datetime.end_of_day
   => Mon, 25 Feb 2013 23:59:59 +0530

  1.9.3dev :063 > d2_eod_datetime == d3_eod_datetime
   => true

and it seems my observation looks correct.That is:

When d1_eod_datetime and d2_eod_datetime are compared it returns false

When d2_eod_datetime and d3_eod_datetime are compared it returns true

It looks like an inconsistent behavior to me, however would appreciate if anybody can make me understand what is going on behind the scenes and why the comparisons made on values using date.end_of_day.to_datetime and date.to_datetime.end_of_day fails though the source date object represents identical date-time.

Thanks,

Jignesh

like image 716
Jignesh Gohel Avatar asked Feb 28 '13 08:02

Jignesh Gohel


1 Answers

Although their string representations are the same, d1_eod_datetime doesn't equal d2_eod_datetime. They differ in their least significant bits. If you convert your datetimes to a float representation, you can see that they're not equal:

d1_eod_datetime.to_f
=> 1381788000.0
d2_eod_datetime.to_f
=> 1381787999.0

The problem occurs when the Time instance receives the end_of_day message. Passing the end_of_day message to the Time instance returns a DateTime instance. The conversion to DateTime might result in a loss of accuracy and the new DateTime instance might not exactly equal to your original Time instance.

like image 130
crazybob Avatar answered Nov 07 '22 21:11

crazybob