Reputation: 10697
currently I'm developing a system that manages work shifts.
The system contains an endpoint that returns the current shift based on server time. I created a query that works fine for regular shifts like 08:00 AM to 04:00 PM and so on but the challenge is when there is a dawn shift that starts at 10:00 PM until 06:00 AM from the other day.
My model contains the following fields:
Ps.: I'm using Postgres as the database.
My code:
class Shift < ApplicationRecord
def self.current
current_time = Time.now()
current_time = current_time.change(year: 2000, month: 1, day: 1)
@current ||= Shift
.where('start_time <= ?', current_time)
.where('end_time >= ?', current_time)
.first()
end
end
Ps.: I guess, since I'm using the Time type in the database, I have to normalize the Time.now to use the 2000 - 01 - 01 date.
So, is there an easy/best way to do that?
Thanks for the help!
Upvotes: 2
Views: 358
Reputation: 1
You might be interested in the tod gem that provides a TimeOfDay
class and a Shift
class that takes two TimeOfDay
objects to represent the start and end of the shift. It handles dawn shifts as expected.
An implementation might look like this:
require 'tod'
class Shift < ApplicationRecord
def self.current
find(&:current?)
end
def current?
schedule.include?(Tod::TimeOfDay(Time.now))
end
def schedule
Tod::Shift.new(Tod::TimeOfDay(start_time), Tod::TimeOfDay(end_time))
end
end
Upvotes: 0
Reputation: 176665
Interesting problem! So there's two cases: (1) a normal shift (where start_time <= end_time
), and (2) a shift that overlaps midnight (where start_time > end_time
).
You are already handling the first case by checking if the current time is between the start time and the end time.
I believe the second case can be handled by checking if the current time is either between the start time and midnight, or between midnight and the end time. Which translates to start_time <= ? OR end_time >= ?
.
I haven't used Rails in a while, but I think you could do something like this:
@current ||= Shift
.where('start_time <= end_time')
.where('start_time <= ?', current_time)
.where('end_time >= ?', current_time)
.or(Shift
.where('start_time > end_time')
.or(Shift
.where('start_time <= ?', current_time)
.where('end_time >= ?', current_time)))
.first()
If you go with this, consider splitting the two cases into separate scopes, so you can write something more readable like this in this method:
@current ||= current_normal_shifts.or(current_dawn_shifts).first
Upvotes: 1