Rails date without year - ruby-on-rails-3

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

Related

domain openerp how to compare 2 date fields in odoo

I create a method when I change a date I received a product and qty to the date of stock.move, I declare start_date = fields.Datetime() in my class
def onchange_project(self, cr, uid,start_date):
"""
onchange handler of start date.
"""
pool_stockmove =self.pool.get('stock.move')
domain =[('date','>=',start_date)]
ids = pool_stockmove.search(cr, uid, domain)
it works fine this method but I want to compare "date of stock" between the start_date date >= start_date AND date <= start_date. I want also to format the date like the method on hr_timesheet
cr.execute('SELECT id \
FROM hr_timesheet_sheet_sheet \
WHERE (date_from <= %s and %s <= date_to) \
AND user_id=%s \
AND id <> %s',(sheet.date_to, sheet.date_from, new_user_id, sheet.id))
if cr.fetchall():
return False
Thanks
Dates are stored in string format. You can compare using sql like in your hr example, but I would suggest compare it using ORM, not raw sql. It is more convenient and it is recommended to always use it, because sql escapes security and other checks that is written in code (but maybe it is not the case in your code).
It's hard to understand which date with which you want to compare and why you can't do it.
I guess you want to do something like this:
[('date', '>=', 'start_date'), ('date', '<=', 'start_date')]
Domain is defined as list of tuples. Such syntax means and is used between tuples on default. You can specify it like this (but it is the same thing):
['&', ('date', '>=', 'start_date'), ('date', '<=', 'start_date')]
It means the same thing as above line (if used '|', means or).
Odoo damains use polish notation: https://en.wikipedia.org/wiki/Polish_notation
And for dates formating, you can use python module datetime to change formatting of date if you need to.
You May try something like this
cr.execute("SELECT id FROM hr_timesheet_sheet_sheet WHERE (date_from >= %s AND date_to <= %s) AND (user_id=%s) AND (id <> %s)",(sheet.date_from,sheet.date_to, new_user_id, sheet.id))
if cr.fetchall():
return False
I hope this should helpful for you :)
this is a simple ex:
employees = self.env['hr.employee'].search([], order='name asc')
for employee in employees:
presence_count = self.env['hr.attendance'].search_count([
('employee_id', '=', employee.id),
('check_in', '>=', date_start_obj.strftime(DATETIME_FORMAT)),
('check_out', '<=', date_end_obj.strftime(DATETIME_FORMAT)),
])
absence_count = date_diff - presence_count
docs.append({
'employee': employee.name,
'presence': presence_count,
'absence': absence_count,
})

SQL select distinct value

I'm trying to select the following data with the limited information. The problem is that when I have added the .select distinct section it has killed my query.
#activities = Availability.select.("DISTINCT user_id").where("team_id = ? and schedule_id = ?", current_user[:team_id], #next_game).last(5)
There's one too many dot's in there as the 'DISTINCT user_id' is the arguments for the select method call.
So:
Availability.select("DISTINCT user_id").where("team_id = ? and schedule_id = ?", current_user[:team_id], #next_game).last(5)
Also be aware that you're now only selecting one attribute and you'll get a partial representation of the classes back. To circumvent this just select the attributes you need later in the code.
Availability.select("DISTINCT(`user_id`), `team_id`").where("team_id = ? and schedule_id = ?", current_user[:team_id], #next_game).last(5)
etc.
Hope this helps.

Rails3 records this year

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

Rails 3 query in multiple date ranges

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)

Is there a way to update an entire array or named_scope without using a loop in ruby on rails?

I create the following array using searchlogic named_scopes:
todos = Todo.asset_is("Email").asset_id_is(self.id)
For each value in the array, there is an attribute called original_date and current_date.
I need to make changes to those with some logic, such as:
difference = (original_date - date_entered) - self.days
original_date = date_entered + self.days
current_date = current_date - different
What I do not want to do is do an each do-loop. But I don't know if there's an alternative -- something like the "update" in SQL (but without needing to use SQL -- like using searchlogic)
Todo.update_all(["original_date = date_entered + %d, current_date = ... + %d",
self.days, self.days], ["id in (?)", todos.map(&:id)])