Skip to content

Instantly share code, notes, and snippets.

@marksim
Last active February 3, 2016 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marksim/16d2874b8754aad9ad9a to your computer and use it in GitHub Desktop.
Save marksim/16d2874b8754aad9ad9a to your computer and use it in GitHub Desktop.
require 'rspec'
require 'date'
class EmploymentEvent < Struct.new(:date, :status)
def <=> (b)
date <=> b.date
end
def as_start
date + 1
end
def as_end
status != :end ? date - 1 : date
end
end
class EmploymentPeriodService
def periods_with_no_employment_changes(employment_periods)
events = inject_events(employment_periods)
events = remove_duplicates(events)
find_ranges(events)
end
private
def inject_events(eps)
[].tap do |events|
eps.each do |ep|
events << EmploymentEvent.new(ep[:start_date], :start)
events << EmploymentEvent.new(ep[:end_date], :end)
end
end
end
def remove_duplicates(events)
events.sort!
[].tap do |sifted_events|
current_event = events.shift
while (!current_event.nil?)
next_event = events.shift
if next_event && next_event.date == current_event.date
if next_event.status != current_event.status
current_event.status = :both
end
else
sifted_events << current_event
current_event = next_event
end
end
end
end
def find_ranges(events)
[].tap do |no_changes_ranges|
events.each.with_index do |e, i|
break if i+1 == events.size
no_changes_ranges << {
start_date: e.as_start,
end_date: events[i+1].as_end
}
end
end
end
end
describe EmploymentPeriodService do
let(:service) { EmploymentPeriodService.new }
it "should return the day after the only start date to the end date given one employee" do
ranges = [
{ start_date: Date.parse('2016-02-02'), end_date: Date.parse('2016-04-09') }
]
expect(service.periods_with_no_employment_changes(ranges)).to eql([{
start_date: Date.parse('2016-02-03'),
end_date: Date.parse('2016-04-09')
}])
end
it "should return proper ranges for multiple employees" do
ranges = [
{ start_date: Date.parse('2016-02-02'), end_date: Date.parse('2016-04-09') },
{ start_date: Date.parse('2016-03-01'), end_date: Date.parse('2016-05-01') }
]
expect(service.periods_with_no_employment_changes(ranges)).to eql([{
start_date: Date.parse('2016-02-03'),
end_date: Date.parse('2016-02-29')
}, {
start_date: Date.parse('2016-03-02'),
end_date: Date.parse('2016-04-09')
}, {
start_date: Date.parse('2016-04-10'),
end_date: Date.parse('2016-05-01')
}])
end
it "should account for multiple people starting the same day" do
ranges = [
{ start_date: Date.parse('2016-02-02'), end_date: Date.parse('2016-04-09') },
{ start_date: Date.parse('2016-02-02'), end_date: Date.parse('2016-05-01') }
]
expect(service.periods_with_no_employment_changes(ranges)).to eql([{
start_date: Date.parse('2016-02-03'),
end_date: Date.parse('2016-04-09')
}, {
start_date: Date.parse('2016-04-10'),
end_date: Date.parse('2016-05-01')
}])
end
it "should account for multiple people starting and ending the same day" do
ranges = [
{ start_date: Date.parse('2016-02-02'), end_date: Date.parse('2016-04-09') },
{ start_date: Date.parse('2016-04-09'), end_date: Date.parse('2016-05-01') },
{ start_date: Date.parse('2016-05-01'), end_date: Date.parse('2016-06-01') },
{ start_date: Date.parse('2016-06-01'), end_date: Date.parse('2016-07-01') }
]
expect(service.periods_with_no_employment_changes(ranges)).to eql([{
start_date: Date.parse('2016-02-03'),
end_date: Date.parse('2016-04-08')
}, {
start_date: Date.parse('2016-04-10'),
end_date: Date.parse('2016-04-30')
}, {
start_date: Date.parse('2016-05-02'),
end_date: Date.parse('2016-05-31')
}, {
start_date: Date.parse('2016-06-02'),
end_date: Date.parse('2016-07-01')
} ])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment