Comparing datetimes for conditional

I just hacked together my first bit of ruby code for pulling in rss feed
items into a database. It uses a conditional which checks the last
item's pubDate against the 'last_checked_at' attribute for the parent
model, 'Source', of the item model. However, I'm getting funny results
when trying to compare times;

if news_item[:pubDate] > @source.last_checked_at do

I'm betting the problem is due to how the datetimes are formatted.

For example, would Ruby consider "Sun Mar 16 16:22:00 +0000 2008" to be
greater than "Sat Mar 15 16:22:00 +0000 2008"? Or do I need to make sure
that the date formats are in year / month / day / time format?

I just hacked together my first bit of ruby code for pulling in rss feed
items into a database. It uses a conditional which checks the last
item's pubDate against the 'last_checked_at' attribute for the parent
model, 'Source', of the item model. However, I'm getting funny results
when trying to compare times;

if news_item[:pubDate] > @source.last_checked_at do

Are these actual instances of Date or Time or are they just strings containing a representation of a time ?
You really don't want to be comparing the strings themselves. (also I'm slightly curious about the 'do' and the end of that line - it's probably not doing what you think it is.

Fred

Frederick Cheung wrote:

I just hacked together my first bit of ruby code for pulling in rss
feed
items into a database. It uses a conditional which checks the last
item's pubDate against the 'last_checked_at' attribute for the parent
model, 'Source', of the item model. However, I'm getting funny results
when trying to compare times;

if news_item[:pubDate] > @source.last_checked_at do

Are these actual instances of Date or Time or are they just strings
containing a representation of a time ?
You really don't want to be comparing the strings themselves. (also
I'm slightly curious about the 'do' and the end of that line - it's
probably not doing what you think it is.

Fred

Thanks for the quick response. I think I'm comparing Time objects
because I had to call Time.parse on the feed pubDate to get Active
Controller to accept the comparison, otherwise it was throwing an error
saying it couldn't compare a String to a Time.

Do you know how Ruby would compare two Time objects from the example in
the first post? And how would you go about comparing two Time objects in
a conditional?

As for the 'do', I made a more detailed post about the RSS parsing and
controller action over on Railsforum,
http://railsforum.com/viewtopic.php?id=16479. I didn't think it was
necessary to include all that info in this thread, but now we're on the
topic, rather than me pasting the same stuff all over the Interwebs,
maybe you could check out the last post in the thread over there and
I'll save the Rails community from a potential cross-threading!

Thanks for the quick response. I think I'm comparing Time objects
because I had to call Time.parse on the feed pubDate to get Active
Controller to accept the comparison, otherwise it was throwing an error
saying it couldn't compare a String to a Time.

Do you know how Ruby would compare two Time objects from the example in
the first post? And how would you go about comparing two Time objects in
a conditional?

You would just do a > b

As for the 'do', I made a more detailed post about the RSS parsing and
controller action over on Railsforum,
http://railsforum.com/viewtopic.php?id=16479. I didn't think it was
necessary to include all that info in this thread, but now we're on the
topic, rather than me pasting the same stuff all over the Interwebs,
maybe you could check out the last post in the thread over there and
I'll save the Rails community from a potential cross-threading!

so what you've got is:

if news_item[:pubDate] > @source.last_checked_at do
   # some stuff
end

(your original indentation rather hides the fact that there are 2 ends).

What this does is call the last_checked_at method on @source, passing the contents of the do-end block as the block to that method (whereas i suspect you think it's the body of the if statement). that block never gets evaluated because last_checked_at doesn't yield to it. If the condition is true then the actual body of the if statement gets executed (ie the bit between the 2 ends) and so nothing happens.

Fred

Frederick Cheung wrote:

the first post? And how would you go about comparing two Time
objects in
a conditional?

You would just do a > b

As for the 'do', I made a more detailed post about the RSS parsing and
controller action over on Railsforum,
http://railsforum.com/viewtopic.php?id=16479. I didn't think it was
necessary to include all that info in this thread, but now we're on
the
topic, rather than me pasting the same stuff all over the Interwebs,
maybe you could check out the last post in the thread over there and
I'll save the Rails community from a potential cross-threading!

so what you've got is:

if news_item[:pubDate] > @source.last_checked_at do
   # some stuff
end
end

(your original indentation rather hides the fact that there are 2 ends).

What this does is call the last_checked_at method on @source, passing
the contents of the do-end block as the block to that method (whereas
i suspect you think it's the body of the if statement). that block
never gets evaluated because last_checked_at doesn't yield to it. If
the condition is true then the actual body of the if statement gets
executed (ie the bit between the 2 ends) and so nothing happens.

Fred

Okay, I understand that - but now I don't know the right way to approach
my problem. I've taken a stab at it, but how would you change the
following action so that it only creates a news_item if the pubDate is
later (greater) than the @source.last_checked_at(?);

   1. class SourceUpdatesController < ApplicationController
   2.
   3. def index
   4. @source = Source.find(:first, :order => "last_checked_at ASC")
   5.
   6. feed = RssParser.run("#{@source.rss_url}")
   7. news_item = feed[:items][0]
   8. news_item[:pubDate] = Time.parse(news_item[:pubDate].to_s)
   9.
  10. # Create a new news_item
  11. if (news_item[:pubDate] > @source.last_checked_at) == true
  12. @news_item = NewsItem.new(:url => news_item[:link],
  13. :title => news_item[:title],
  14. :creator => news_item[:creator],
  15. :published_at =>
news_item[:pubDate],
  16. :description =>
news_item[:description],
  17. :source_id => @source.id)
  18. @news_item.save
  19. end
  20.
  21. @source.update_attribute(:last_checked_at, Time.now)
  22. end
  23.
  24. end

Okay, I understand that - but now I don't know the right way to
approach
my problem. I've taken a stab at it, but how would you change the
following action so that it only creates a news_item if the pubDate is
later (greater) than the @source.last_checked_at(?);

just
if news_item[:pubDate] > @source.last_checked_at
   #do stuff
end

Should be enough. If it's not working, check that the time is getting
parsed properly. Also check that the save isn't failing.

Fred

Frederick Cheung wrote:

Okay, I understand that - but now I don't know the right way to
approach
my problem. I've taken a stab at it, but how would you change the
following action so that it only creates a news_item if the pubDate is
later (greater) than the @source.last_checked_at(?);

just
if news_item[:pubDate] > @source.last_checked_at
   #do stuff
end

Should be enough. If it's not working, check that the time is getting
parsed properly. Also check that the save isn't failing.

Fred

Thanks Fred. Obviously it was working with and without "== true", I just
made the mistake of comparing the pubDate to the last_checked_at date
without considering the possibility of the timezone from which the feed
is published being ahead of that on my local machine. The action was
duplicating news_items for one feed because of the time difference, and
that's why I thought it wasn't working correctly.

There probably is a better way to tackle this, but for now I'm storing
an additional 'last_item_published_at' attribute for the Source, and
using that in the conditional instead. I imagine the attribute will come
in handy further down the line, anyway. Although, I now need to work out
how to handle this attribute when a 'source' is created. Maybe I'll do
an initial check on the feed pubDate in the 'create' action. Could I use
the same helpers that Rails uses to handle the defaults for created_at
and updated_at but with an additional DateTime attribute? Or do you have
a better suggestion?

p.s. How would you go about checking RSS feeds for updates? Would you
use something wildly different to what I have?