我们将如何存储和查询营业时间?
我们正在构建一个存储各种业务的"营业时间"的应用程序。表示此数据的最简单方法是什么,以便我们可以轻松检查项目是否打开?
一些选项:
- 分割出可以标记为"打开/关闭"的块(每隔15分钟)。检查包括查看"开路"位是否设置了所需的时间(有点像火车时刻表)。
- 存储时间范围的列表(上午11点至下午2点,下午5点至晚上7点等),并检查当前时间是否落在任何指定的范围内(这是我们的大脑在解析上面的字符串时所做的事情)。
是否有人在存储和查询时间表信息以及提供任何建议方面有经验?
(有各种各样的疯狂案例,例如"本月的第一个星期二关闭",但我们将其保留另一天)。
解决方案
存储每个连续的时间块作为开始时间和持续时间;这样可以更方便地检查小时数是否超出了日期范围
如果我们确定营业时间永远不会超出日期范围(即永远不会有通宵营业或者72小时马拉松比赛等),那么开始/结束时间就足够了
最灵活的解决方案可能是使用位集方法。每周有168个小时,因此有672个15分钟。只有84字节的空间值得,这是可以容忍的。
段块更好,只需确保我们为用户提供了一种简单的设置方式。单击并拖动是好的。
当我们越过午夜边界时,任何其他系统(例如范围)都会非常烦人。
至于存储它们的方式,在C ++位域中可能是最好的。在大多数其他语言中,数组可能会更好(浪费了很多空间,但运行得更快,更容易理解)。
当然,这里不需要保留内存,但是可能需要干净且可理解的代码。恕我直言,"摇摆不定"不是要走的路。
我们在这里需要一个固定的容器,该容器可容纳任意数量的唯一项目,并且可以快速轻松地确定某个项目是否为成员。该安装程序需要注意,但是在日常工作中,使用简单理解的一行代码即可确定我们是打开还是关闭
概念:
从例如星期日午夜开始,每隔15分钟分配一次索引号。
初始化:
打开时,将每隔15分钟的块的索引号插入一组。 (假设营业时间少于营业时间。)
使用:
减去有趣的时间(以分钟为单位,从上个星期日的午夜开始),然后除以15. 如果该数字存在于集合中,则表示我们处于开放状态。
我想我个人会考虑开始和结束时间,因为这会使一切变得更加灵活。一个很好的问题是:块大小在特定点发生变化的机会是多少?然后选择最适合我们情况的解决方案(如果有可能更改的话,我会尽力解决这个问题)。
我们可以将它们存储为时间跨度,并在应用程序中使用细分。这样,我们就可以使用块轻松输入数据,同时保持更改数据存储区的灵活性。
我现在会稍微考虑一下这些极端情况,因为它们将告知我们是否具有基本配置以及覆盖或者完全静态存储开放时间或者其他内容。
有很多例外情况,并且定期(例如下雪天,不定期假期(例如复活节,耶稣受难日)),如果期望这是现实的可靠表示(而不是一个好的猜测),则需要在架构中很快解决它。
我会用这样的表:
BusinessID | weekDay | OpenTime | CloseTime --------------------------------------------- 1 1 9 13 1 2 5 18 1 3 5 18 1 4 5 18 1 5 5 18 1 6 5 18 1 7 5 18
在这里,我们的业务正常营业时间为5到6,但星期日的营业时间较短。
查询是否打开(psuedo-sql)
SELECT @isOpen = CAST (SELECT 1 FROM tblHours WHERE BusinessId = @id AND weekDay = @Day AND CONVERT(Currentime to 24 hour) IS BETWEEN(OpenTime,CloseTime)) AS BIT;
如果我们需要存储边缘案例,那么每天只有365个条目...在大事情上确实不那么多,在day列和businessId列上放置一个索引。
不要忘记将企业时区存储在单独的表中(规范化!),并在进行这些比较之前在时间和时间之间进行转换。
除了约翰娜森·霍兰德(Johnathan Holland)所说的,我将允许同一天进行多次输入。
我也将允许使用十进制时间,或者在另一列中输入分钟。
为什么?许多餐馆和一些企业,以及世界各地的许多企业都有午餐和/或者下午休息时间。另外,许多餐厅(据我所知,有2家餐厅是在我的房子附近以不增加15的奇数时间关闭的。一家餐厅在周日的9:40 PM停业,而另一家则在1:40 AM停业。
还有假期的问题,例如,商店在感恩节早早关闭,因此我们需要基于日历的覆盖。
也许可以做的是打开日期/时间,关闭日期/时间,例如:
businessID | datetime | type ========================================== 1 10/1/2008 10:30:00 AM 1 1 10/1/2008 02:45:00 PM 0 1 10/1/2008 05:15:00 PM 1 1 10/2/2008 02:00:00 AM 0 1 10/2/2008 10:30:00 AM 1
等等(类型:1为打开,0为关闭)
并提前1-2年预先计算未来1或者2年中的所有天数。请注意,我们将只有3列:int,日期/时间/位,因此数据消耗应最小。
这也使我们可以将特殊日期的奇数小时的特定日期修改为已知的日期。
它还负责穿越午夜以及12/24小时转换。
它也是时区不可知的。如果存储开始时间和持续时间,则在计算结束时间时,机器是否会为我们提供TZ调整时间?那是你要的吗?更多代码。
就查询打开/关闭状态而言:查询相关的日期时间,
select top 1 type from thehours where datetimefield<=somedatetime and businessID = somebusinessid order by datetime desc
然后看"类型"。如果为1,则为打开;如果为0,则为关闭。
PS:我从事零售业已有10年了。因此,我熟悉小型企业的疯狂工作时间问题。
这样的事情怎么样:
营业时间表
Business_id (int) Start_Time (time) End_Time (time) Condition varchar/string Open bit
"条件"是lambda表达式(" where"子句的文本)。动态建立查询。因此,对于特定企业,我们可以选择所有打开/关闭时间
Let Query1 = select count(open) from store_hours where @t between start_time and end_time and open = true and business_id = @id and (.. dynamically built expression) Let Query2 = select count(closed) from store_hours where @t between start_time and end_time and open = false and business_id = @id and (.. dynamically built expression)
因此,结束时我们需要以下内容:
select cast(Query1 as bit) & ~cast(Query2 as bit)
如果最后一个查询的结果为1,则存储在时间t打开,否则关闭。
现在,我们只需要一个友好的界面即可为我们生成where子句(lambda表达式)。
我能想到的唯一一个极端的情况是,如果商店在某个日期从早上7点到凌晨2点营业,但在第二天的晚上11点关门,将会发生什么情况。系统应该也可以通过巧妙地划分两天之间的时间来处理此问题。