在数据库中存储工作时间


84

我目前正在尝试找出将业务运营时间存储在数据库中的最佳方法。

例如:

商家A有以下营业时间

  • 星期一:9am-5pm
  • 星期二:上午9点至下午5点
  • 星期三:上午9点至下午5点
  • 星期四:上午9点至下午5点
  • 星期五:上午9点至下午5点
  • 星期六:上午9点至中午12点
  • 周日:休息

目前,我有一个类似于以下内容的数据模型

CREATE TABLE "business_hours" (
    "id" integer NOT NULL PRIMARY KEY,
    "day" varchar(16) NOT NULL,
    "open_time" time,
    "close_time" time
)

其中“天”仅限于代码中一周中7天的选择(通过ORM)。为了测试企业是否在某一天关门,它会检查open_time和close_time是否为NULL。它通过中间表(多对多关系)与业务相关。

有没有人对此数据库方案有任何建议?对我来说似乎有些不对劲。


4
为什么在business_hours表和businesss表之间需要M对M的关系?如果您真的要让多个企业在business_hours中共享相同的记录,那为什么呢?从语义上讲,“公司C在D天从T1到T2工作”这一事实实际上是一个价值对象,而不是一个实体……我能想到的唯一好的(?)原因是存储大小优化(Flyweight模式的RDB版本,可以这么说),如果企业数量预计会很大……
Yarik

2
午休时间怎么样?公众假期呢?
Mawg说恢复Monica's

Answers:


56

总体而言,我认为这没有错。除了...

  1. 我会使用本机编程语言使用的任何编号系统(在其库中)将整数存储为一个整数。这将减小数据库的大小,并从代码中删除字符串比较。

  2. 我可能会将外键放在此表中的业务表中。这样,您将不需要链接表。

所以我想我会这样做:

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
)

按照我的业务逻辑,我将强制执行一个约束,即每个“业务”至少要有7个“工作时间”。(至少因为Jon Skeet是正确的,所以您可能需要放假时间。)尽管您可能想通过在营业时间以外的时间里简单地取消“营业时间”来放松这种限制。


1
你会怎么做2?即使日期/时间相同,所有业务的所有条目都存在吗?
Vinko Vrsalovic

7
我会说是的。否则,请考虑如果两个公司碰巧共享同一小时数,但是其中之一需要更改其小时数会发生什么。您将必须检测小时数已更改的事实,然后根据是否共享记录来创建新记录或编辑现有记录。
Erik Forbes

3
我绝对不会在企业之间共享该表的行。这种共享只会导致痛苦。应用程序的业务逻辑应仅强制执行约束,即每个业务至少具有7个“ business_hours”引用。
Frank Krueger 2009年

1
@Vinko:请记住,虽然(当前)相同,但是两家公司的营业时间在语义上是不同的。
Draemon

1
您还可以将“天”使用7位的位图。这样,您不必重复相同的输入例如所有工作日都具有相同的工作时间,一个输入就足够了。
ZolaKt

28

此架构未涵盖的一种情况是一天中有多个开放期。例如,当地酒吧开放时间为12:00-14:30和17:00-23:00。

也许剧院票房是开放的,可以放映电影并进行晚间表演。

此时,您需要确定是否可以在同一天输入多个条目,或者是否需要在同一行中代表不同的小​​时数。

午夜过后的开放时间呢?假设酒吧在19:00-02:00开放。您不能仅将打开和关闭时间与要测试的时间进行比较。


我最终做了@JordanFeldstein建议的事情。我存储“状态更改”数组,其中包括更改(打开或关闭),星期几和一天中的时间。我可以为每个业务和每天进行任意数量的“更改”。一家公司可以一天营业,第二天营业,每天营业两次(或x次),每天营业24小时,但周一营业。实施起来很棘手,但非常灵活。
ironcito

按照最佳答案的方法,我宁愿在business_hoursbreak_time和添加两列break_duration。在同一天休息2次真的很罕见。
Frondor

12

它的种类取决于您需要存储的内容以及实际数据的外观。
如果您需要确定业务在某个特定时间是否已营业,则查询所设计的方案可能会有些尴尬。但是,更重要的是:您是否需要迎合中午休假?

一些选项包括:

  • 类似于您的计划,但可以选择在同一天有多个期间。它可以满足午休时间的需求,但是会给您提供给定一天的开放时间(例如要向用户展示)的查询的麻烦。
  • 位图样式方法;9-5的“ 000000000111111110000000”。这种方法的缺点是您必须选择特定的粒度,即整个小时或半小时,或者实际上是几分钟。粒度越细,对人来说数据越难读取。您可以使用按位运算符将该值存储为单个数字,而不是整数字符串,但这又会损害可读性。

11

我了解到,如果您想让Google数据标记识别您的数据,则应遵循以下准则:

https://schema.org/openingHours

http://schema.org/OpeningHoursSpecification包含“有效日期”,这对某些企业非常有用。

https://schema.org/docs/search_results.html#q=小时

没有主键的情况应该没问题,除非您允许企业与联接表共享相同的时间-有趣的是,最终您将获得有限数量的组合;我不确定会有多少:p

在我的一个项目中,我使用了以下列:

[uInt] business_id,[uTinyInt] day,[char(11)] timeRange

如果要支持OpeningHoursSpecification,则需要添加validFrom和validThrough。

时间范围的格式如下:hh:mm-hh:mm

这是一个解析它的函数,如果您将其保留为数据库中的单独列,则还可以修改此函数以仅解析一个打开/关闭。

根据我的经验,我建议您在一天之内允许多次,允许您确定当日它们是明确关闭还是24小时或24/7营业。我曾经说过,如果数据库中缺少一天,那么该天该业务将关闭。

/**
 * 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;
}

1

对于给定的方案,大多数结果都可以正常工作,但是,如果您的期间要经过数天,那么效果就不会那么好。8:00 AM〜2:00 AM,然后建议您使用多周期设计。

   0: [
         id: 1,
         business_id: 1,
         open: true,
         day: 1,
         periods: [
             0: { open: 08:00, close: 23:59 }
         ]
      ],
   1: [
         id: 2,
         business_id: 1,
         open: true,
         day: 2,
         periods: [
             0: { open: 00:00, close: 02:00 }
             1: { open: 08:00, close: 23:59 }
         ]
      ]

0

可能考虑通过将月份/月份/月份/月份中的其他字段包括在内来考虑假期。一个月中的某周有一些小巧之处,“最后”例如可以是第4周或第5周,具体取决于年份。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.