Different time transitions

The maximum precision of times in Ruby is in the nanosecond range. So 0.000000001 second. This is the same for Time, as for DateTime.
However, Ruby on Rails has a different understanding of the end of the day when it comes to the nanoseconds.

Times in Rails

Ruby on Rails has extended the time classes with useful functionalities. For example, end_of_day:

# => Sun, 20 Nov 2016 23:59:59 +0100
# => 2016-11-20 23:59:59 +0100

Attention! Whenever the time zone is relevant, Time.current is your friend.

The problem in Rails

Since Time as well as DateTime deal with nanoseconds:

# => 249095319
# => 483323251

It is assumed that the end of a day is the same for objects of both classes:

RSpec.describe '#end_of_day' do
  it 'returns the same milliseconds as DateTime' do
    expect(Time.now.end_of_day.nsec).to eq(DateTime.now.end_of_day.nsec)

But that is not true:

1) #end_of_day returns always same milliseconds
       expected: 0
            got: 999999999
1 example, 1 failure

The problem: the end of a day for Time is exactly 999999999 nanoseconds later than it is for DateTime.

The implementation

This difference seems somewhat unexpected, but is actually wanted. The implementation at both classes:

# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 173
def end_of_day
    :hour => 23,
    :min => 59,
    :sec => 59,
    :usec => Rational(999999999, 1000)

# File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 113
def end_of_day
  change(:hour => 23, :min => 59, :sec => 59)

Therefore it is recommended to favor Time over DateTime when it comes to the end of day. Because according to DateTime a time between 23:59:59 and 24:00:00 is undefined: it is neither before the end of the day nor after the beginning of a day:

(DateTime.tomorrow.beginning_of_day - 0.1.second) < DateTime.now.end_of_day
# => false

The same applies to all time transitions. So all day endings (#end_of_month and #end_of_year), but also #end_of_hour and #end_of_minute.

Update - 2017-03-05:

The Rails Core Team has fixed the inconsistency. The PR #28242 has been merged. It is expected that DateTime will also set the usec for all end_of methods with Rails version 5.1.