From 7cccdd2006ff8245e78c2ef567109be4389acb5e Mon Sep 17 00:00:00 2001 From: bohung Date: Thu, 21 Jul 2022 23:31:58 +0800 Subject: [PATCH] Accelerate recurring events calculating. --- app/models/event.rb | 111 +++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 57 deletions(-) diff --git a/app/models/event.rb b/app/models/event.rb index 80e8dad..10756a2 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -17,6 +17,7 @@ class Event field :recurring, type: Boolean,default: false field :frequency field :period + field :recurring_end_date, type: DateTime field :create_user_id field :update_user_id field :module_key @@ -147,69 +148,65 @@ class Event (date2.year-date1.year)*12+(date2.month-date1.month) end def self.recurring_event(start_date,end_date) - @recurring_events = self.where(:recurring => true) + @recurring_events = self.where(:recurring => true).any_of({:recurring_end_date=>nil}, {:recurring_end_date.gte=>start_date.utc}) @recurring = [] @recurring_events.each do |re| - edit_url = Rails.application.routes.url_helpers.edit_admin_calendar_path(:locale=>I18n.locale, :id=>re.id) - delete_url = Rails.application.routes.url_helpers.admin_calendar_path(:locale=>I18n.locale, :id=>re.id) - data = {:id => re.id.to_s, :title=>re.title, :note=>re.note || "", :allDay => re.all_day, :recurring => re.recurring, :calendar => re.calendar_type.id.to_s, :color => (re.calendar_type.color rescue nil), :edit_url => edit_url, :delete_url => delete_url, :url_linked => re.url_to_fronted} - case re.period - when 'Daily' - days = (end_date.to_date-re.start.to_date).to_i + has_recurring_end_date = re.recurring_end_date.present? + data = re.as_json + period_str = nil + is_month = false + is_year = false + days = 1 + interval = nil + if re.period == 'Daily' + period_str = 'day' + interval = 1.day + elsif re.period == 'Weekly' + period_str = 'week' + days = 7 + interval = 1.week + elsif re.period == 'Monthly' + period_str = 'month' + is_month = true + days = 30 + elsif re.period == 'Yearly' + period_str = 'year' + is_year = true + days = 365 + end + if period_str + org_start = re.start + @start_date = re.start + @end_date = re.end freq = re.frequency.to_i - start_key = (start_date.to_date-re.start.to_date).to_i - start_key = 1 if start_key<0 - (start_key..days).each do |i| - if i%freq==0 - @start_date = re.start + i - @end_date = re.end + i - @recurring << data.merge({:start => @start_date, :end => @end_date}) - end + interval = freq.send(period_str) + if is_month + add_interval = ((start_date.year * 12 + start_date.month) - (@start_date.year * 12 + @start_date.month) - 1) + elsif is_year + add_interval = (start_date.year - @start_date.year - 1) + else + add_interval = (((start_date - @start_date - 1.day).to_i / 1.day) / days) end - when "Weekly" - @start_date = re.start - @end_date = re.end - @i = TimeDifference.between(re.start.to_date,end_date.to_date).in_weeks.to_i - (1..@i).each do |i| - @start_date += (7*re.frequency.to_i) - @end_date += (7*re.frequency.to_i) - @recurring << data.merge({:start => @start_date, :end => @end_date}) - end - when "Monthly" - if !(start_date..end_date).cover?(re.start) && start_date.to_datetime>re.start - sd = re.start - ed = re.end - end_datetime = end_date.to_datetime - start_datetime = start_date.to_datetime - months = self.get_diff_month(sd,start_datetime)..self.get_diff_month(sd,end_datetime) - months.each do |diff_month| - if (diff_month%re.frequency.to_i)==0 - sd_tp = sd + diff_month.month - ed_tp = ed + diff_month.month - if sd_tp>start_date - @recurring << data.merge({:start => sd_tp, :end => ed_tp}) - end - end - end + if add_interval < 0 + add_interval = add_interval % freq end - when "Yearly" - if !(start_date..end_date).cover?(re.start) - sd = re.start - ed = re.end - start_datetime = start_date.to_datetime - end_datetime = end_date.to_datetime - if start_datetime>sd && start_datetime.year != sd.year - ((start_datetime.year-sd.year)..(end_datetime.year-sd.year)).each do |year_diff| - if (year_diff%re.frequency.to_i)==0 - sd_tp = sd + year_diff.year - ed_tp = ed + year_diff.year - if (start_date..end_date)&(sd_tp..ed_tp) - @recurring << data.merge({:start => sd_tp, :end => ed_tp}) - end - end - end - end + rest = add_interval % freq + if rest != 0 + add_interval += (freq - rest) end + add_interval = add_interval.send(period_str) + @start_date += add_interval + @end_date += add_interval + new_end_date = has_recurring_end_date ? [re.recurring_end_date,end_date].min : end_date + while @start_date <= new_end_date do + if @start_date >= start_date && @start_date != org_start + @recurring << data.merge({:start => @start_date.to_json.gsub('"',''), :end => @end_date.to_json.gsub('"','')}) + end + @start_date += interval + @end_date += interval + end + else + next end end