Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding annual dates with Rails 3.1 ActiveRecord Queries

I am building a Rails 3.1 project in which one of my models contains a birthday attribute. I have been trying to find a query that essentially finds all users with a birthday within a certain range. The problem is that this part of the application doesn't really care about the year of birth, just the month and day. Unfortunately, Google has not been of much help on this one.

Does anyone know how to query for all records whose birthday attribute "has an anniversary" within a certain date range? I hope that makes sense!

like image 634
Andrew Avatar asked Nov 24 '25 14:11

Andrew


1 Answers

Sounds like you're looking for EXTRACT:

M.where(%q{
    array[extract(month from d)::int, extract(day from d)::int] between array[?, ?] and array[?, ?]
}, lower_month, lower_day, upper_month, upper_day)

where M is your model, bday is the birthday column, and the upper and lower variables hold the month and day boundaries. You could also use INTERSECT:

M.find_by_sql([%q{
    select * from ms where array[? ,?] <= array[extract(month from bday)::int, extract(day from bday)::int]
    intersect
    select * from ms where array[?, ?] >= array[extract(month from bday)::int, extract(day from bday)::int]
}, lower_month, lower_day, upper_month, upper_day])

Yet another version would use to_char:

M.where(
    "to_char(bday, 'MM') || to_char(bday, 'DD') between ? and ?",
    '%2.2d%2.2d' % [lower_month, lower_day],
    '%2.2d%2.2d' % [upper_month, upper_day]
)

You could get the same results with a big ugly pile of CASE statements too (so that you'd only consider the day-of-month at the month boundaries) but the the intersection is (IMO) cleaner and easier to read. Using the (PostgreSQL) arrays allows you to compare the month/day pairs with each other as single units rather than separately.

like image 160
mu is too short Avatar answered Nov 27 '25 06:11

mu is too short



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!