I have a Location that can have Events. I want to have an upcoming_events method but want it to round down such that if someone looks at 10pm at night, it will show todays events. I have this:
def upcoming_events
d=Time.new
d.strftime("%m-%d-%Y")
l=Event.where('location_id=? and start_datetime>?',self.id, d)
end
I gets converted down correctly but in d.strftime but the query is:
SELECT `events`.* FROM `events` WHERE (location_id=301 and start_datetime>'2012-06-20 02:49:23')
Any idea how to just get it to do '2012-06-20'?
Calling strftime does essentially nothing here, since it doesn't change the d object in any way.
Anyway, Rails provides the method beginning_of_day on DateTime (as well as Date & Time) that does exactly what you want:
d = Time.now #=> 2012-06-19 23:05:54 -0400
d.beginning_of_day #=> 2012-06-19 00:00:00 -0400
So just change your code to:
Event.where('location_id=? and start_datetime>?', self.id, d.beginning_of_day)
I think you actually meant "%Y-%m-%d" vice "%m-%d-%Y" since you wanted '2012-06-20'. As such, try the following:
def upcoming_events
d=Time.new
l=Event.where('location_id=? and start_datetime>?', self.id, d.strftime("%Y-%m-%d"))
end
Related
The goal is to compare timestamp to a range of times.
The range of times were defined in the rails schema as t.time for postgresql database. However the data returned upon querying the console attributes a date to the record's field...
start_time: "2000-01-01 08:00:00"
end_time: "2000-01-01 17:59:59"
Now if I want to validate whether a record created_at: "2017-03-18 03:44:04" is in the time range, I am also comparing the date, which is throwing the query into empty-array-land.
What rails or ruby tools can be used in this case in a database-agnostic manner?
def within_time_range?(start_time, end_time, time_check)
t = time_check[11..-1]
t >= start_time[11..-1] && t <= end_time[11..-1]
end
start_time = "2000-01-01 08:00:00"
end_time = "2000-01-01 17:59:59"
within_time_range?(start_time, end_time, "2017-03-18 03:44:04")
#=> false
within_time_range?(start_time, end_time, "2017-03-18 09:05:01")
#=> true
within_time_range?(start_time, end_time, "2017-03-18 19:05:01")
#=> false
Note
start_time[11..-1]
#=> "08:00:00"
I've used String#<= and String#>=, which are obtained from String#<=> and the inclusion of the module Comparable into the String class.
You could force every time object to be parsed at the same date (e.g. 1st of january 2000) :
require 'time'
def parse_time_not_date(string)
time = Time.parse(string)
Time.local(2000, 1, 1, time.hour, time.min, time.sec, time.usec)
end
start_time = parse_time_not_date("2000-01-01 08:00:00")
end_time = parse_time_not_date("2000-01-01 17:59:59")
my_time = parse_time_not_date("2017-03-18 03:44:04")
puts (start_time..end_time).cover?(my_time)
# false
puts (start_time..end_time).cover?(parse_time_not_date("2017-03-18 14:59"))
# true
I am going to chime in, as the discussion from the first answer was pertinent. Cary's answer works for that case. The question was ambivalent in terms of possible solutions: ruby or rails. And hence some potential gum ups. What follows is another way.
With rails, there is an issue in considering time zones. Calling an object of data type time actually stays in UTC. With date_time you are getting a string with + or - hours(or fraction thereof - yay Newfoundland!)
So, processing with rails, the proper way to handle UTC data is to assign it the rails application time zone with in_time_zone, chain to string and then extracting. Thus, comparisons ended up as:
p = Time.parse(#interruptions[0].pause.to_s[11,8])
p >= Time.parse(d_s.start_time.in_time_zone.to_s[11,8]) && p <= Time.parse(d_s.end_time.in_time_zone.to_s[11,8])
Note: could not get [11..-1] working in this context
I have a Rails 3.2 app with an Article model that has a field for date. I want to create a scope that will retrieve all records from last month. The problem I'm having is that my current scope is not including the first day of the month.
# article.rb
scope :last_month, lambda { { conditions: { date: last_month_range } } }
private
def self.last_month_range
1.month.ago.beginning_of_month..1.month.ago.end_of_month
end
When I run this it does this:
SELECT * FROM 'articles' WHERE ('articles`.'date' BETWEEN '2013-07-01 07:00' AND '2013-08-01 06:59:59')
When I look at the actual results it only starts with the articles with a date of 07-02-2013.
However, if I change the code to:
def self.last_month_range
(1.month.ago.beginning_of_month - 1.day)..1.month.ago.end_of_month
end
It does this:
SELECT * FROM 'articles' WHERE ('articles`.'date' BETWEEN '2013-06-30 07:00' AND '2013-08-01 06:59:59')
In that case it pulls in articles with dates of 6/31/2013.
Can someone please recommend a fix? Thank you!
ActiveRecord does the conversion automatically to UTC, unless you have specified otherwise. You need to convert the range to UTC.
def self.last_month_range
1.month.ago.utc.beginning_of_month..1.month.ago.utc.end_of_month
end
I got bit by a bug in the accepted answer:
Time.now.utc # => 2015-05-01 01:18:57 UTC
1.month.ago.utc.beginning_of_month #=> 2015-03-01 00:00:00 UTC
The problem is that the time is being converted to utc after the month is subtracted.
Here's a correct solution:
def self.last_month_range
Time.now.utc.prev_month.beginning_of_month..Time.now.utc.prev_month.end_of_month
end
In my controller I have:
#konkurrencer = Rating.new(params[:kon])
#konkurrencer.save
#konkurrencer.konkurrencer.rating_score += params[:kon][:ratings].to_i
#konkurrencer.konkurrencer.ratings += 1
#konkurrencer.created_at = Time.now.strftime("%Y-%m-%d 00:00:00")
#konkurrencer.save
When I create a new item it the created_at column is:
2012-02-27 16:35:18
I would expect it to be:
2012-02-27 00:00:00
Your problem is that strftime only formats the time, it doesn't actually change the time.
So when you do Time.now, that returns the time. Strftime only changes the way that its represented.
If you wanted to change the created_at date to "2012-02-27 00:00:00", just pass that in to #koncurrencer.created_at
#koncurrencer.created_at = "2012-02-27 00:00:00"
That should do it.
In response to your question:
What you were doing should work just fine then. In fact you can just say:
#koncurrencer.created_at = Time.now
#koncurrencer.save
and that should work just fine.
If you wanted to always have the time be at the beginning of the day you could use Date.today instead of Time.now since that always returns the time component of the Date as "00:00:00"
Here is what you want:
#koncurrencer.created_at = Date.today
#koncurrencer.save
That should be more clear.
If you want to set the time always to "00:00:00", you can go by this:
t = Time.now
=> 2012-02-27 17:46:38 +0100
t2 = Time.parse("00:00:00", t)
=> 2012-02-27 00:00:00 +0100
I am implementing a full text search API for my rails apps, and so far have been having great success with Thinking Sphinx.
I now want to implement a date range search, and keep getting the "bad value for range" error.
Here is a snippet of the controller code, and i'm a bit stuck on what to do next.
#search_options = { :page => params[:page], :per_page => params[:per_page]||50 }
unless params[:since].blank?
# make sure date is in specified format - YYYY-MM-DD
d = nil
begin
d = DateTime.strptime(params[:since], '%Y-%m-%d')
rescue
raise ArgumentError, "Value for since parameter is not a valid date - please use format YYYY-MM-DD"
end
#search_options.merge!(:with => {:post_date => d..Time.now.utc})
end
logger.info #search_options
#posts = Post.search(params[:q], #search_options)
When I have a look at the log, I am seeing this bit which seems to imply the date hasn't been converted into the same time format as the Time.now.utc.
withpost_date2010-05-25T00:00:00+00:00..Tue Jun 01 17:45:13 UTC 2010
Any ideas? Basically I am trying to have the API request pass in a "since" date to see all posts after a certain date. I am specifying that the date should be in the YYYY-MM-DD format.
Thanks for your help.
Chris
EDIT: I just changed the date parameters merge statement to this
#search_options.merge!(:with => {:post_date => d.to_date..DateTime.now})
and now I get this error
undefined method `to_i' for Tue, 25 May 2010:Date
So obviously there is something still not setup right...
lets say d = "2010-12-10"
:post_date => (d.to_time.to_i..Time.now.to_i) would have gotten you there. I just did this in my project and it works great
I finally solved this, but it takes a slightly different approach but it works fine.
I was trying to put the date-range search inside a sphinx_scope (in the model) or as a :condition or :with (in the controller). This did not work, so instead I had to implement it inside the define_index in the model.
So what I did was put a check in the define_index to see if a record fell within a date range, the date range being defined by some SQL code, as shown below. In this case, I wanted to see if "start_date" fell within a date between now and 30 days ago, and an "end_date" fell within today and 30 days from now.
If the dates fell within the ranges, the code below causes the :live to be 0 or 1, depending on whether it falls outside or inside the date ranges (respectively):
define index do
# fields:
...
# attributes:
has "CASE WHEN start_date > DATE_ADD(NOW(), INTERVAL -30 DAY) AND end_date < DATE_ADD(NOW(), INTERVAL 30 DAY) THEN 1 ELSE 0 END", :type => :integer, :as => :live
...
# delta:
...
end
Then in your controller, all you have to do is check if :live => 1 to obtain all records that have start_dates and end_dates within the date ranges.
I used a sphinx_scope like this:
sphinx_scope(:live) {
{ :with => { :live => 1 } }
}
and then in my controller:
#models = Model.live.search(...)
To make sure it works well, you of course need to implement frequent reindexing to make sure the index is up to date, i.e. the correct records are :live => 1 or 0!
Anyway, this is probably a bit late for you now, but I implemented it and it works like a charm!!!
Wouldn't it work if you replaced
d = DateTime.strptime(params[:since], '%Y-%m-%d')
by
Time.parse(params[:since]).strftime("%Y-%m-%d")
(It seems the first one doesn't return a date in the expected format)
I'm implementing the Timezone support in Rails 2.1+, and I've run into an apparent bug in the way the data is pulled from the db. Let me try to set it up.
The "deals" model contains an "offer_date" datetime field. Let's say I have two records with these offer_dates:
Deal 1: 2009-12-29 23:59:59 -0500
Deal 2: 2009-12-28 23:59:59 -0500
This is correct: dates should mark the last second of its given day.
Now, when it comes time to find the deal for today, I have the following AR query:
#deal = Deal.first(:conditions=>['offer_date > ?', Time.now.beginning_of_day], :order=>"offer_date ASC")
In this case, although it's the 29th today, it returns the record ostensibly for the 28th. Why? Here's what happens in the console:
>> #deal = Deal.first(:conditions=>['offer_date > ?', Time.now.beginning_of_day], :order=>"offer_date ASC")
=> #<Deal id: 2, <blah blah blah...>, offer_date: "2009-12-29 04:59:00">
It's shifting the time forward by 5 hours, putting yesterday's day into the next. But when I do this:
>> #deal.offer_date
=> Mon, 28 Dec 2009 23:59:00 EST -05:00
I get the right time. What the heck??? Suffice to say, I need that date to work properly, but I can't figure out where my issue is. Any assistance you can provide would be greatly appreciated!
See my prior rsponse on Time vs Time.zone for AR date queries.
Instead of using Time.now, try using Time.zone.now
Of course you have to set this and everything. This tutorial seems helpful.
the Time class doesn't care about the time zone in the implementation of #to_s, therefore you have to use
Time.zone.now # or any other TimeWithZone object
in your finders/named_scopes/find calls. Or you could read through http://marklunds.com/articles/one/402 and then put
module ActiveRecord
module ConnectionAdapters # :nodoc:
module Quoting
# Convert dates and times to UTC so that the following two will be equivalent:
# Event.all(:conditions => ["start_time > ?", Time.zone.now])
# Event.all(:conditions => ["start_time > ?", Time.now])
def quoted_date(value)
value.respond_to?(:utc) ? value.utc.to_s(:db) : value.to_s(:db)
end
end
end
end
into your environment.rb or into an initializer.