# 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)