Reputation: 1079
I'm currently trying to work out the best way to store a business' hours of operation in a database.
For example:
Business A has the following hours of operation
Currently I'm have a data model similar to the following
CREATE TABLE "business_hours" (
"id" integer NOT NULL PRIMARY KEY,
"day" varchar(16) NOT NULL,
"open_time" time,
"close_time" time
)
where the "day" is restricted to a choice of the 7 days of the week in code (through the ORM). To test if a business is closed on a certain day it checks if the open_time and close_time are NULL. It is related to the business through a intermediate table (Many To Many Relationship).
Does any one have any suggestions for this database scheme? Something about it doesn't seem right to me.
Upvotes: 106
Views: 53929
Reputation: 429
Most of results works fine for the given scenario, but it wont be as effective if you have periods that runs through multiple days, eg. 8:00 AM ~ 2:00 AM, then I recommend using a multi period design.
{
id: 1,
day: 1,
periods: [
0: { open: 08:00, close: 00:00 }
]
},
{
id: 2,
day: 2,
periods: [
0: { open: 08:00, close: 00:00 }
1: { open: 00:00, close: 02:00 }
]
}
day: number of day of the week
if no periods, means it is closed
Upvotes: 8
Reputation: 14783
I have learned that if you want to have google data markup recognize your data you should follow these guidelines:
https://schema.org/openingHours
http://schema.org/OpeningHoursSpecification Contains "valid dates", which is very useful for some businesses.
https://schema.org/docs/search_results.html#q=hours
You should be fine without a primary key, unless you are allowing businesses to share the same hours with the join table - interestingly eventually you would have a finite amount of combinations; I'm not sure how many that would be :p
With one of my projects I used the columns:
[uInt]business_id, [uTinyInt]day, [char(11)]timeRange
If you want to support OpeningHoursSpecification then you'll need to add validFrom and validThrough.
Time Range is formatted like: hh:mm-hh:mm
Here's a function that parses it, you can also modify this function to parse just a single open/close, if you keep them as separate columns in the DB.
Out of my experience I would recommend that you allow multiple times within a day, allow for a way to tell if they are explicitly closed on that day, or opened 24 hours or 24/7. I had mine say that if there was a day missing in the DB then the business was closed that day.
/**
* parseTimeRange
* parses a time range in the form of
* '08:55-22:00'
* @param $timeRange 'hh:mm-hh:mm' '08:55-22:00'
* @return mixed ['hourStart'=>, 'minuteStart'=>, 'hourEnd'=>, 'minuteEnd'=>]
*/
function parseTimeRange($timeRange)
{
// no validating just parsing
preg_match('/(?P<hourStart>\d{1,2}):(?P<minuteStart>\d{2})-(?P<hourEnd>\d{1,2}):(?P<minuteEnd>\d{2})/', $timeRange, $matches);
return $matches;
}
Upvotes: 17
Reputation: 40045
One situation that isn't covered by this schema is several opening periods in a day. For example, the local pub is open 12:00-14:30 and 17:00-23:00.
Maybe a theatre box office is open for a matinee and an evening performance.
At that point you need to decide if you can have several entries for the same day, or if you need to represent different hours in the same row.
What about opening times that cross midnight. Say a bar is open 19:00-02:00. You couldn't just compare the opening and closing times with the time you want to test.
Upvotes: 37
Reputation: 70983
Overall, I see nothing wrong with this. Except...
I would store the day of week as an integer using whatever numbering system your native programming language uses (in its libraries). This will decrease the size of the database and remove string comparisons from your code.
I would probably put the foreign key to the business table right here in this table. That way you won't need a link table.
So I guess I would do:
CREATE TABLE "business_hours" (
"id" integer NOT NULL PRIMARY KEY,
"business_id" integer NOT NULL FOREIGN KEY REFERENCES "businesses",
"day" integer NOT NULL,
"open_time" time,
"close_time" time
)
In my business logic, I would enforce a constraint that every "business" has at least 7 "business hours". (At least because Jon Skeet is right, you might want holiday hours.) Though you may want to relax this constraint by simply leaving off "business hours" for days that the business is closed.
Upvotes: 76
Reputation: 4538
Might think about factoring in holidays by including additional fields for month of year/day of month/week of month. Week of month has some minor subtlties "last" could for example be week 4 or 5 depending on the year.
Upvotes: 0
Reputation: 7438
It sort of depends on what you need to store it for and what the real-world data could look like.
If you need to be able to determine if the business is open at a certain point then it may be a bit awkward to query the scheme as laid out. More importantly, though, is: Would you ever need to cater for a mid-day closure?
Some options include;
Upvotes: 16