ActiveSupport::Duration and #end_of_day

Hello all :smiley:

I am struggling with ActiveSupport::Duration and creation of a duration that matches the #end_of_day. Summarised in code as follows:

Date.today.end_of_day == Date.today + ActiveSupport::Duration.parse("PT23H59M59.999999S") #=> false

I need only the duration (there is no date within the context where the duration is built)

I have tried ::build method without success

ActiveSupport::Duration.build((1440 * 60) - 0.0000000001.second)

Both these Duration instanciation methods are nearly correct, only nano seconds out.

Can anyone suggest something I can try to construct a Duration that can be used to match #end_of_day ?? :sos:

More code to demo my issue:

def end_duration
  ActiveSupport::Duration.parse("PT23H59M59.999999S")
end

date = Date.new(2022, 1, 1)
date_with_duration = date + end_duration

# both dates appear the same..
date.end_of_day.to_s == date_with_duration.to_s #=> true
# .. but they are not
date.end_of_day == date_with_duration #=> false
# looks like itd down the second fraction
date.end_of_day.sec_fraction #=> (999999999/1000000000)
date_with_duration.sec_fraction #=> (8796084226115/8796093022208)

Found the answer :sweat_smile:

ActiveSupport::Duration.build(Rational(86399.999999999 * 1000, 1000))

1 Like

For your comparison using .to_s(), if you want to see down to microseconds (millionths of a second) then check using .strftime('%Y-%m-%d_%H.%M.%S.%6N %Z') instead, like this:

date.end_of_day.strftime('%Y-%m-%d_%H.%M.%S.%6N %Z') == date_with_duration.strftime('%Y-%m-%d_%H.%M.%S.%6N %Z') #=> false

And for nanoseconds (billionths of a second), in the strftime formatting string change the 6 to a 9 like this: .strftime('%Y-%m-%d_%H.%M.%S.%9N %Z')

1 Like