Max Williams
Max Williams

Reputation: 32945

Select records where start_date and end_date cross a given day of the year, regardless of year

I'm trying to find a way to neaten this up. I have a collection of License records, loaded already from data. Each has a start_date and end_date field. I want to select those that cross a given date, in any year. (when i say they cross that date, i mean start_date is before the date and end_date is after the date).

Here's the clunky way i'm doing it at the moment, which uses an array of that same date in different years, going back 10 years and forward 10 years.

target_date = Date.parse("30-09-2015")
date = target_date - 10.years
dates = []
while date < 10.years.from_now
  dates << date
  date += 1.year
end
#now have an array `dates` of Date objects holding eg ["30-09-2005", 30-09-2006", ... "30-09-2025"]
crossing_licenses = licenses.select{|license| dates.detect{|date| license.start_date < date && license.end_date > date}}

This works but it feels like there must be a much more elegant way to do it. Thanks, Max

PLEASE NOTE: i start with the collection of licenses already, and so i'm NOT looking for how to do an sql query to get these licenses.

EDIT: potential gotcha - watch out for a licence starting the previous year, eg that goes from "10-10-2014" to "30-10-2015".

Upvotes: 0

Views: 139

Answers (1)

Yury Lebedev
Yury Lebedev

Reputation: 4015

I would say that you don't need an array with dates to do this:

target_date = Date.parse("30-09-2015")

crossing_licenses = licenses.select do |license|
  return false if license.end_date < 10.years.ago
  return false if license.start_date > 10.from_now

  (license.start_date..license.end_date).any? do |date|
    date.month == target_date.month && date.day == target_date.day
  end
end

Just make sure, that the start_date and end_date are actually Date objects, and not Time. If so, it is better to convert them to dates, otherwise you will get huge ranges.

Upvotes: 1

Related Questions