|
|
# frozen_string_literal: true
|
|
|
|
|
|
require "date"
|
|
|
|
|
|
class AcademicYear < ActiveRecord::Base
|
|
|
scope :by_range, -> { all.map { |academic_year| [academic_year.range, academic_year] }.to_h }
|
|
|
scope :of_year, ->(range) { all.select { |ay| ay.range.start_with?(range) } }
|
|
|
|
|
|
def self.range_from_date(date, ranges)
|
|
|
year = parse_year_range(date:)
|
|
|
range = ranges.find { |item| item.downcase == "#{year.start}-#{year.end.to_s[2, 3]} #{year.season.downcase}" }
|
|
|
range ||= ranges.find { |item| item.downcase == "#{year.start}-#{year.end.to_s[2, 3]}" }
|
|
|
range
|
|
|
end
|
|
|
|
|
|
def formatted_range
|
|
|
years = range.split("-").map(&:split).flatten
|
|
|
"#{years.first} – 20#{years.second} #{years[2]}".chomp
|
|
|
end
|
|
|
|
|
|
def range_without_season
|
|
|
range.scan(/[\d-]/).join
|
|
|
end
|
|
|
|
|
|
private
|
|
|
|
|
|
def self.parse_year_range(date:)
|
|
|
year = date.year
|
|
|
ayr = if date.month > 6
|
|
|
AcademicYearRange.new(year, year + 1)
|
|
|
else
|
|
|
AcademicYearRange.new(year - 1, year)
|
|
|
end
|
|
|
|
|
|
ayr.season = if in_fall?(date, ayr)
|
|
|
"Fall"
|
|
|
else
|
|
|
"Spring"
|
|
|
end
|
|
|
ayr
|
|
|
end
|
|
|
|
|
|
def self.in_fall?(date, ayr)
|
|
|
date.between?(Date.parse("#{ayr.start}-7-1"), last_sunday(2, ayr.end) - 1)
|
|
|
end
|
|
|
|
|
|
# returns a Date object being the last sunday of the given month/year
|
|
|
# month: integer between 1 and 12
|
|
|
def self.last_sunday(month, year)
|
|
|
# get the last day of the month
|
|
|
date = Date.new year, month, -1
|
|
|
# subtract number of days we are ahead of sunday
|
|
|
date -= date.wday
|
|
|
end
|
|
|
|
|
|
private_class_method :in_fall?
|
|
|
private_class_method :parse_year_range
|
|
|
end
|
|
|
|
|
|
AcademicYearRange = Struct.new(:start, :end, :season)
|