Rails - Time arithmetic - ruby-on-rails

I was playing time arithmetic in rails console. I have subtracted two different times and got back a long number, please see below my code.
a = User.find(1).updated_at # returns Mon, 03 Mar 2014 11:07:43 UTC +00:00
b = User.find(1).created_at # returns Mon, 03 Mar 2014 08:36:50 UTC +00:00
a - b # returns 9053.699814796448
My question is. What is this number 9053.699814796448? Is it time? What is it's unit? and how is that calculated? Is it possible to change the default unit of the outcome?
Thanks

a - b gives you the time in seconds. Check out the Time#- .

Related

How does Rails handle comparison between TimeWithZone and Date objects?

This could introduce subtle "bugs" (perceived inconsistencies), like the following:
>> Time.zone.parse('Tue, 01 Aug 2017 00:00:00 CEST +02:00') < Date.new(2017,8,1)
=> true
It seems as if Rails converts the Date to a DateTime or TimeWithZone object with '00:00:00 UTC', hence the result. Like this:
>> Date.new(2017,8,1).to_datetime
=> Tue, 01 Aug 2017 00:00:00 +0000
That would explain it. But I would like to know how Rails actually does this, and what type of object it converts it to in the process, to be sure. I didn't find it in the API docs, or the source, but maybe someone can give a step by step explanation.
The source I looked through was: compare_with_coercion
PS: To me it would seem saner that in this type of comparison that Rails would actually convert the TimeWithZone object to a Date object instead, thus resulting in only the date portions to be compared, so that:
>> Time.zone.parse('Tue, 01 Aug 2017 00:00:00 CEST +02:00') == Date.new(2017,8,1)
=> true
Ref:
DateTime API doc
Date API doc

Invalid date getting displayed in rails

I know it is common error but I could not resolve it even after trying those answers.
Through the rest api I am sending some parameters inculdes dates. I am recieving all the data in the method where I want but when I am trying to parse Date it throws error of invalid date.
Here are my parameters that I am recieving
{"uid"=>"1", "user"=>"abc.a#abc.com", "from"=>"Mon Nov 3 24:59:12 CET 2014", "to"=>"Tue Nov 11 24:59:12 CET 2014"}
and Date format is
Mon Nov 3 24:59:12 CET 2014
but it is throwing error on parsing on line below
fr = DateTime.parse(params[:from]) unless params[:from].empty?
I tried strptime as well but did not work.
Imp points is I need hour also for later processing. Thanks
what you are doing wrong is parsing DateTime while it is just date and should be parsed as one of the following ways:
1.
>> fr = params[:from].to_date unless params[:from].empty?
=> Mon, 03 Nov 2014
2.
>> fr = Date.parse(params[:from]) unless params[:from].empty?
=> Mon, 03 Nov 2014
You have 24:59 which is invalid time. Anyway, use strptime:
DateTime.strptime("Mon Nov 3 22:59:12 CET 2014", "%a %b %e %T %Z %Y")
#=> Mon, 03 Nov 2014 22:59:12 +0100

Effect of leaving space after '-' in Ruby expression

Today I was trying something out in my Rails console and this happened,
2.0.0p247 :009 > Date.today -29.days
=> Fri, 07 Feb 2014
2.0.0p247 :010 > Date.today - 29.days
=> Thu, 09 Jan 2014
I am pretty baffled. I can see that I am missing something basic. But it just inst striking my mind! Could anyone explain why this is happening?
What actually happens is this:
Date.today(-29.days) # => Fri, 07 Feb 2014
today has an optional parameter called start, which defaults to Date::ITALY.
An optional argument the day of calendar reform (start) as a Julian
day number, which should be 2298874 to 2426355 or -/+oo. The default
value is Date::ITALY (2299161=1582-10-15).
Passing -29.days to today apparently has no effect.
Whereas:
Date.today + -29.days # => Thu, 09 Jan 2014
Which is the same as:
Date.today - 29.days # => Thu, 09 Jan 2014
The Fixnum#days method in Ruby is defined in the ActiveSupport library in Rails. More specifically, it's defined in the 'active_support/core_ext/numeric/time` module
Just loading ActiveSupport inside a console
> require 'active_support'
true
> require 'active_support/core_ext'
true
> 29.days
=> 2505600
> -29.days
=> -2505600
The code for the method days looks like this:
def days
ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
end
The self object in this case is 29 or -29. That gets multiplied by 2505600 which is a legitimate calculation and will return the amount of seconds that the number 29 represents.
With that in mind, in the first calculation, you're just passing two objects to the console input, the first one being a Date object and the second one being a number. Similar to sending the following:
> puts "test"
That is, the -29.days is passed as an argument to the object returned byDate.today. And Date.today accepts a parameter which specifies the start day of the calendar. Refer to this answer to know the accepted days. If any non-recognized parameter is passed, the default start date is used (which is Date::GREGORIAN)
> Date.today
=> Thu, 09 Feb 2014
> Date.today Date::JULIAN
=> Fri, 25 Jan 2014
So Ruby checks if you passed in a valid start date constant or not and the decide on the start date. For this reason, you still get today's date as the answer when running the first command.
The second command is simply the subtraction of one Date object with another object that is understood by Ruby as the number of seconds you want to subtract from today's date. 29.days is internally converted to the number of seconds in both cases.
Hope that helps.

Why does this DateTime subtraction operation return invalid results?

I have two DateTime objects, one in the past and one representing the current datetime. I am trying to find out how many minutes have passed between the two:
past = "Wed, 03 Jul 2013 00:59:39 UTC +00:00".to_datetime
now = "Wed, 03 Jul 2013 01:04:19 +0100".to_datetime
seconds = (now - past) #result is (-83/2160)
This is incorrect. Seconds should be 280, the number of seconds that have passed between the two times.
Subtracting two DateTimes returns the elapsed time in days.
So you can do:
past = "Wed, 03 Jul 2013 00:59:39 UTC +00:00".to_datetime
now = "Wed, 03 Jul 2013 01:04:19 +0100".to_datetime
seconds = (now - past) * 1.day
# => -3320.0
Or you could do:
seconds = (now.to_i - past.to_i)
# => -3320
※ The result is negative because of the Timezone.
past.utc
# => Wed, 03 Jul 2013 00:59:39 +0000
now.utc
# => Wed, 03 Jul 2013 00:04:19 +0000
You can see that now is actually older than past.

Why is `from_now` wrong when called on a Fixnum?

I need to store some time periods in a yaml file, like this:
test:
testing: <%= 1.month %>
I grab the data in an initializer like this:
Class::TIMES = YAML.load(ERB.new(File.new(Rails.root.join('config', 'times.yml')).read).result)
So far so good. But the times I get from this are always off by a day; testing shows this. For example:
<Tue, 06 Mar 2012> expected but was <Wed, 07 Mar 2012>.
The test line:
assert_equal 1.month.from_now.to_date, #object.finished_at.to_date
Elsewhere, #object's finished_at is set like this:
# duration is from the YAML file
self.finished_at = duration.from_now
It always seems to be off by a day, no matter what time period I put in the YAML file. Why does this happen?
EDIT: This seems to be an issue with Fixnums and from_now:
> 1.month.from_now
=> Tue, 06 Mar 2012 21:05:00 UTC +00:00
> 1.month.to_i.from_now
=> Wed, 07 Mar 2012 21:05:05 UTC +00:00
When you convert 1.month to an integer it arbitrary sets the duration getting passed into from_now to 2592000 seconds i.e 30 days regardless of what month it is.
I ran into this issue once before. Check out the documentation for the Data and Time Helper Methods .
While these methods provide precise calculation when used as in the
examples above(".. 1.month.from_now .."), care should be taken to note
that this is not true if the result of months’,years’, etc is
converted before use

Resources