Scenario: I want to get the nearest time in relation to my system time.
I have written the following method inside my model:
def self.nearest_class(day, teacher_id, hour_min)
day_of_week = '%' + day + '%'
if hour_min == "06:00:00"
where('frequency like ? AND teacher_id = ? AND (start_time >= ?)', day_of_week, teacher_id, hour_min).order('start_time ASC')
else
where('frequency like ? AND teacher_id = ? AND (start_time >= localtime(0))', day_of_week, teacher_id).order('start_time ASC')
end
end
When I tested the above method in rails console using Lecture.nearest_class('Monday', 1, 'localtime(0)'), the following query was returned together with some data:
SELECT "lectures".* FROM "lectures" WHERE (frequency like '%Monday%' AND teacher_id = 1 AND (start_time >= localtime(0))) ORDER BY start_time ASC
But I am expecting no record because my system time is greater than any start_time recorded in the database. I have used the query from the console to pgadmin3 to test if the results are same. However, pgadmin3 showed no results, as expected.
Are there differences in postgresql time and rails app time? How can I be able to check these differences? I tried Time.now in the console and it is the same as SELECT LOCALTIME(0) from pgadmin3. What should be the proper way to get the records for nearest system time?
To further set the context, here's my controller method:
def showlectures
#teacher = Teacher.login(params[:id]).first
#lecture_by_course = nil
if #teacher
WEEKDAY.each do |day|
hour_min = "06:00:00"
if day == Time.now.strftime("%A") # check if day of week is same e.g. 'Monday'
hour_min = "localtime(0)" # system time with format: HH:MM:SS
end
#lecture_by_course = Lecture.nearest_class(day, #teacher.id, hour_min).first
if #lecture_by_course
break
end
end
end
render json: #lecture_by_course, include: { course: { only: [:name, :id] }}
end
I solved this by just passing the server Time.now instead of having a SQL check. { :| d'oh }
Related
I have query, that would return me data depending on its created_at timestamp
my query looks like
condition[:created_at] = " > #{Time.now - 2.days}"
model.where(condition)
and this return me following sql
...WHERE `model`.`created_at` = ' > 2000-01-01T02:00:00+02:00'
so here timestamp looks different from what in db
So how do i pass correct timestamp to match AR format?
ActiveSupport's #ago will help:
model.where("created_at > ?", 2.days.ago)
Also, I wrote a gem to contain common scopes for created_at queries and others: https://github.com/neighborland/scopy
I want to query my db for objects of an arbitrary model created on a certain day, what's a good way to do this?
In an sql query I used the following to query the objects created yesterday.
where (created_at AT TIME ZONE 'EDT') > (now() AT TIME ZONE 'EDT')::DATE - 1
and (created_at AT TIME ZONE 'EDT') < (now() AT TIME ZONE 'EDT')::DATE
I want to do the same thing in ruby with ActiveRecord calls.
Thanks!
An example, as a scope, for all items that were created today:
scope :created_today, -> { where('created_at between ? AND ?', Time.zone.now.beginning_of_day, Time.zone.now.end_of_day) }
More information at the PostgreSQL site
I would do the cast on the database and select the current date there, instead of doing it with a range. You can do this with DATE(created_at) (Will result in "2013-11-01") Then inject the param in the where:
Model.where("DATE(created_at) = ?", Date.today)
If it's used on more places then one it would be good to create a scope as Morner suggested:
scope :created_today { where("DATE(created_at) = ?", Date.today) }
with name:
scope :created_today_with_name lambda do |name|
where("DATE(created_at) = ? AND name = ?", Date.today, name)
end
or chain it:
scope :created_today_with_name lambda do |name|
where("DATE(created_at) = ?", Date.today).where(name: name)
end
Then call it as:
Model.created_today_with_name('Joe')
In Rails3 how do I retrieve all records that have a date of this year?
I'd like to retrieve all my "Projects" where the "date" is this year.
I would suspect it would be something similar to:
#projects_this_year = Project.where(:date.Time.year == Time.now.year)
or
#projects_this_year = Project.where(:date >= ?, Time.now.year)
I'm reading through the docs, but haven't quite figured this out yet.
You could do something like this (Assuming a MySQL DB):
#projects_this_year = Project.where("year(date) = ?", Time.now.year)
or better:
#projects_this_year = Project.where("year(date) = year(utc_timetamp())")
which doesn't require loading the time library.
For reference: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
Edit
If you want it to be database independent then you can do something like this:
#projects_this_year = Project.where("date >= ?", Time.now.at_beginning_of_year)
You could also make this dynamic in the model if you needed specific months or years often or through params by expanding on #David's answer:
def self.get_year(date)
# sanitize if params
safe = ['2011', '2012', '2013']
if safe.include?(date)
where("year(created_at) = ?", Time.parse("#{date}-01-01 11:11:11 -0500").year)
else
scoped
end
end
EX:
Product.get_year('2012')
NOTE to get this to work on heroku please change the following:
where("date_part('year', created_at) = ?", Time.parse("#{date}-01-01 11:11:11 -0500").year
http://www.java2s.com/Code/PostgreSQL/Date-Timezone/datepartyeardate.htm
Suppose we have some date ranges, for example:
ranges = [
[(12.months.ago)..(8.months.ago)],
[(7.months.ago)..(6.months.ago)],
[(5.months.ago)..(4.months.ago)],
[(3.months.ago)..(2.months.ago)],
[(1.month.ago)..(15.days.ago)]
]
and a Post model with :created_at attribute.
I want to find posts where created_at value is in this range, so the goal is to create a query like:
SELECT * FROM posts WHERE created_at
BETWEEN '2011-04-06' AND '2011-08-06' OR
BETWEEN '2011-09-06' AND '2011-10-06' OR
BETWEEN '2011-11-06' AND '2011-12-06' OR
BETWEEN '2012-01-06' AND '2012-02-06' OR
BETWEEN '2012-02-06' AND '2012-03-23';
If you have only one range like this:
range = (12.months.ago)..(8.months.ago)
we can do this query:
Post.where(:created_at => range)
and query should be:
SELECT * FROM posts WHERE created_at
BETWEEN '2011-04-06' AND '2011-08-06';
Is there a way to make this query using a notation like this Post.where(:created_at => range)?
And what is the correct way to build this query?
Thank you
It gets a little aggressive with paren, but prepare to dive down the arel rabbit hole
ranges = [
((12.months.ago)..(8.months.ago)),
((7.months.ago)..(6.months.ago)),
((5.months.ago)..(4.months.ago)),
((3.months.ago)..(2.months.ago)),
((1.month.ago)..(15.days.ago))
]
table = Post.arel_table
query = ranges.inject(table) do |sum, range|
condition = table[:created_at].in(range)
sum.class == Arel::Table ? condition : sum.or(condition)
end
Then, query.to_sql should equal
(((("sessions"."created_at" BETWEEN '2011-06-05 12:23:32.442238' AND '2011-10-05 12:23:32.442575' OR "sessions"."created_at" BETWEEN '2011-11-05 12:23:32.442772' AND '2011-12-05 12:23:32.442926') OR "sessions"."created_at" BETWEEN '2012-01-05 12:23:32.443112' AND '2012-02-05 12:23:32.443266') OR "sessions"."created_at" BETWEEN '2012-03-05 12:23:32.443449' AND '2012-04-05 12:23:32.443598') OR "sessions"."created_at" BETWEEN '2012-05-05 12:23:32.443783' AND '2012-05-21 12:23:32.443938')
And you should be able to just do Post.where(query)
EDIT
You could also do something like:
range_conditions = ranges.map{|r| table[:created_at].in(r)}
query = range_conditions.inject(range_conditions.shift, &:or)
to keep it a little more terse
I suggest you try the pure string form:
# e.g. querying those in (12.months.ago .. 8.months.ago) or in (7.months.ago .. 6.months.ago)
Post.where("(created_at <= #{12.months.ago} AND created_at >= #{8.months.ago} ) OR " +
"(created_at <= #{7.months.ago} AND created_at >= #{6.months.ago} )" )
In your case, I would suggest to use mysql IN clause
Model.where('created_at IN (?)', ranges)
How can I find a record by date, but without the year?
this is what I have :
#date = Date.today
#article = Article.find_by_date(#date)
But really what I wanna do is search for an article that by only the month and the day. The year is not important.
Tested with SQLite:
Model.find(:all, :conditions => ["STRFTIME('%m-%d', field_name) = '?-?'", 12, 25])
The generated query illustrates how this finds everything where field_name is Christmas:
Model Load (16.1ms) SELECT "models".* FROM "models" WHERE (STRFTIME('%m-%d', field_name) = '12-25')
I also had success with the shorter "field_name LIKE '%-MM-DD'" but this was MySQL; according to its manual, it indeed uses strings to read and write dates. YMMV.
I suspect this is dependent on which database you're using. Different implementations have different names/syntax for the EXTRACT or DATE_PART function. On PostgreSQL, this one works:
Model.where('EXTRACT(month FROM field_name) = ? AND EXTRACT(day FROM field_name) = ?', 12, 25)
You can do:
Model.all.where(["DAY(`date`) = ? AND MONTH(`date`) = ?", Date.current., 12])
Simple!
A DB agnostic approach would be to add attributes to your model for date_month and date_day (and set them with a before_save callback). Something like:
before_save :set_date_day_and_month
def set_date_day_and_month
self.date_month = date.month
self.date_day = date.day
end
#untested
Then you can do straight-forward queries that wouldn't involve db-specific functions. Like:
Article.where('date_month = ? AND date_day = ?', 12, 25)
#for articles on Christmas
Or:
Article.where('date_month = ? AND date_day = ?', Date.today.month, Date.today.day)
#for articles on this date any year