-
-
Save liushooter/a37c736b4d8d917a1d12 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source 'https://rubygems.org' | |
gem 'activesupport' | |
gem 'rspec-rails' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'active_support' | |
require 'active_support/core_ext' | |
class Schedule | |
NO_REPEAT = 0 | |
R_DAY = 1 | |
R_WDAY = 2 | |
R_WEEK = 3 | |
R_MONTH = 4 | |
EOL = 10.years.since | |
attr_accessor :current_start, :current_end | |
def initialize start_time:, end_time:, repeat: 0, last_time: nil | |
@start_time = start_time | |
@end_time = end_time | |
@repeat = repeat | |
@last_time = last_time | |
@current_start = @start_time | |
@current_end = @end_time | |
end | |
# return: nil if no next, else a schedule start from next date | |
def next_time! | |
return if @current_start.nil? | |
return @current_start = nil if @repeat == NO_REPEAT | |
offset = 0 | |
case @repeat | |
when R_DAY then offset = 1.day | |
when R_WDAY then offset = @current_start.wday == 5 ? 3.days : 1.day | |
when R_WEEK then offset = 7.days | |
when R_MONTH then offset = find_next_month_offset | |
end | |
duration = @current_end - @current_start | |
@current_start += offset | |
@current_end = @current_start + duration | |
return @current_start = nil if @last_time && @current_start > @last_time | |
return @current_start = nil if @current_start > EOL | |
@current_start | |
end | |
# next month at the end of the month could be more than 1 month offset | |
# next month of 3/31 is 5/31 | |
def find_next_month_offset | |
length = 0 | |
this_month = @current_start | |
loop do | |
length += 1 | |
next_month = this_month + length.months | |
break if next_month.day == this_month.day | |
end | |
length.month | |
end | |
def conflicts? sch | |
# @start within sch? | |
return true if @current_start >= sch.current_start && @current_start <= sch.current_end | |
# @end within sch? | |
return true if @current_end >= sch.current_start && @current_end <= sch.current_end | |
# @ contains sch? | |
return true if @current_start <= sch.current_start && @current_end >= sch.current_end | |
# safe | |
false | |
end | |
end | |
class ScheduleService | |
def self.conflicts? s1, s2 | |
# if both schedule exists? | |
while !s1.current_start.nil? && !s2.current_start.nil? | |
# check if they conflicts | |
return true if s1.conflicts? s2 | |
# find the next date to compare | |
if s1.current_start < s2.current_start | |
s1.next_time! | |
else | |
s2.next_time! | |
end | |
end | |
false | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require './main' | |
describe Schedule do | |
it 'generates future events by month' do | |
t = Time.new(2015,1,31) | |
s = Schedule.new start_time: t, end_time: t + 40.minutes, repeat: 4, last_time: t + 1.year | |
tlist = [] | |
while !s.current_start.nil? do | |
tlist << s.current_start | |
s.next_time! | |
end | |
expect(tlist.size).to eq 8 | |
end | |
it 'generates future events by week' do | |
t = Time.new(2015,1,31) | |
s = Schedule.new start_time: t, end_time: t + 40.minutes, repeat: 3, last_time: t + 1.year | |
tlist = [] | |
while !s.current_start.nil? do | |
tlist << s.current_start | |
s.next_time! | |
end | |
expect(tlist.size).to eq 53 | |
end | |
it 'generates future events by workday' do | |
t = Time.new(2015,2,2) # It's monday | |
s = Schedule.new start_time: t, end_time: t + 40.minutes, repeat: 2, last_time: t + 1.month | |
tlist = [] | |
while !s.current_start.nil? do | |
tlist << s.current_start | |
s.next_time! | |
end | |
expect(tlist.size).to eq 21 | |
end | |
it 'generates future events by day' do | |
t = Time.new(2015,1,31) | |
s = Schedule.new start_time: t, end_time: t + 40.minutes, repeat: 1, last_time: t + 1.month | |
tlist = [] | |
while !s.current_start.nil? do | |
tlist << s.current_start | |
s.next_time! | |
end | |
expect(tlist.size).to eq 29 | |
end | |
end | |
describe ScheduleService do | |
it '日程【2015-07-08 16:00:00,2015-07-08 17:00:00,不重复】与日程【2015-07-06 16:00:00,2015-07-06 16:30:00,每天重复,没有截止日期】冲突' do | |
s1 = Schedule.new start_time: Time.new(2015, 7, 8, 16), end_time: Time.new(2015, 7, 8, 17) | |
s2 = Schedule.new start_time: Time.new(2015, 7, 6, 16), end_time: Time.new(2015, 7, 6, 16, 30), repeat: Schedule::R_DAY | |
expect(ScheduleService.conflicts? s1, s2).to be true | |
end | |
it '日程【2015-07-08 16:00:00,2015-07-08 17:00:00,每工作日重复,没有截止日期】与日程【2015-07-11 16:00:00,2015-07-11 17:00:00,每周重复,没有截止日期】 不冲突' do | |
s1 = Schedule.new start_time: Time.new(2015, 7, 8, 16), end_time: Time.new(2015, 7, 8, 17), repeat: Schedule::R_WDAY | |
s2 = Schedule.new start_time: Time.new(2015, 7, 11, 16), end_time: Time.new(2015, 7, 11, 17), repeat: Schedule::R_WEEK | |
expect(ScheduleService.conflicts? s1, s2).to be false | |
end | |
it '日程【2015-05-31 16:00:00,2015-05-31 17:00:00,每月重复,截止2015-07-15】与日程【2015-06-10 16:00:00,2015-06-10 17:00:00,每天重复,没有截止日期】不冲突' do | |
s1 = Schedule.new start_time: Time.new(2015, 5, 31, 16), end_time: Time.new(2015, 5, 31, 17), repeat: Schedule::R_MONTH, last_time: Time.new(2015, 7, 15) | |
s2 = Schedule.new start_time: Time.new(2015, 6, 10, 16), end_time: Time.new(2015, 6, 10, 17), repeat: Schedule::R_DAY | |
expect(ScheduleService.conflicts? s1, s2).to be false | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment