您将如何存储和查询营业时间?

时间:2008-09-26 21:58:15

标签: language-agnostic datetime time time-management

我们正在构建一个应用程序,为各种业务存储“营业时间”。表示此数据的最简单方法是什么,以便您可以轻松检查项目是否已打开?

一些选项:

  • 分割出可以标记为“打开/关闭”的块(每15分钟一次)。检查涉及查看“开放”位是否设置了所需的时间(有点像火车时刻表)。
  • 存储时间范围列表(上午11点至下午2点,下午5-7点等)并检查当前时间是否落在任何指定范围内(这是我们的大脑在解析上述字符串时所做的事情)。

是否有人有存储和查询时间表信息的经验以及任何建议?

(有各种各样的疯狂角落案例,例如“关闭了本月的第一个星期二”,但我们会将其留下另一天)。

10 个答案:

答案 0 :(得分:5)

将每个连续的时间块存储为开始时间和持续时间;这样可以更轻松地检查小时数何时跨越边界

如果您确定操作小时数永远不会超过日期限制(即永远不会有开放式夜间销售或72小时马拉松赛事等),那么开始/结束时间就足够了

答案 1 :(得分:3)

最灵活的解决方案可能是使用bitset方法。一周有168小时,所以有672个15分钟的时间段。那只有84个字节的空间,应该是可以容忍的。

答案 2 :(得分:2)

我会使用这样的表:

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小时,但周日时间较短。

if open的查询将是(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个条目,每天一个......在宏观方案中真的没那么多,在日期列和businessId列上放置一个索引。

不要忘记将商家时区存储在一个单独的表中(规范化!),并在进行这些比较之前在您的时间与之间进行转换。

答案 3 :(得分:1)

我想我会亲自去开始和结束时间,因为它会让一切变得更加灵活。一个很好的问题是:块大小在某一点上会发生什么变化?然后选择最适合您情况的解决方案(如果它可能会发生变化,我肯定会选择时间跨度)。

您可以将它们存储为时间跨度,并在应用程序中使用细分。这样,您可以使用块轻松输入,同时保持数据存储区更改的灵活性。

答案 4 :(得分:1)

要添加Johnathan Holland said,我会在同一天允许多个条目。

我还允许小数时间,或者其他列分钟。

为什么呢?许多餐馆和一些企业,以及世界各地的许多企业都有午餐和下午休息时间。此外,许多餐馆(我知道在我家附近的2家餐厅以非15个增量的时间收盘。一个在星期日晚上9:40关闭,一个在凌晨1:40关闭。

还有假日时间的问题,例如在感恩节早期关闭的商店,所以你需要有基于日历的覆盖。

也许可以做的是日期/时间开放,日期时间关闭,例如:

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
然后看看“类型”。如果一个,它是开放的,如果为0,它就会关闭。

PS:我在零售店工作了10年。所以我熟悉小企业的疯狂小时问题。

答案 5 :(得分:1)

好的,我会因为它的价值而投入其中。

我需要处理很多事情。

  • 快速/高效查询
  • 任何时间增量,9:01 PM,12:14等
  • 国际(?) - 不确定这是否是一个问题,即使是时区,至少在我的情况下,但在这里更精通的人可以自由地加入
  • 打开 - 关闭跨越到第二天(中午开放,凌晨2:00关闭)
  • 多个时间间隔/天
  • 能够覆盖特定日期(假期,等等)
  • 重写的能力
  • 能够查询任何时间点并使企业开放(现在,未来时间,过去时间)
  • 能够轻松排除即将关闭的业务结果(过滤业务在30分钟后关闭,您不想让您的用户和那个在关闭食品/饮料行业前5分钟出现的人) )

我喜欢提出的很多方法,而且我从其中一些方法借用。在我的网站,项目中,无论我需要考虑什么,我可能拥有数百万家企业,而且这里的一些方法似乎并不适合我个人。

这是我对算法和结构的建议。

我们必须随时随地在全球范围内做出一些具体的假设: 一周有7天。 一天有1440分钟。 可能存在有限数量的开/关分钟排列。

不是具体但体面的假设: 开放/关闭会议记录的许多排列将在企业之间共享,从而减少实际存储的总排列。 在我生命中有一段时间我可以很容易地计算出这种方法的实际可能组合,但如果有人可以协助/认为它会有用,那就太棒了。

我建议3桌: 在你停止阅读之前,请考虑在现实世界中这些表中的2个将足够小的缓存整齐。由于将UI解释为数据模型所需的代码非常复杂,并且如果需要,可以再次返回,因此这种方法并不适用于所有人。您的里程和需求可能会有所不同这是对合理的企业的尝试。等级解决方案,无论这意味着什么。

HoursOfOperations表

ID |打开(分钟)|关闭(一天一分钟)


1 | 360 | 1020(例如:上午9点至下午5点)

2 | 365 | 1021(例如:边缘情况9:05 AM - 5:01 PM(怪人))

HoursOfOperations并不关心什么日子,只是开放和关闭以及独特性。每个开/关组合只能有一个条目。现在,根据您的环境,这整个表可以被缓存,也可以缓存当天的当前小时等。无论如何,您不需要为每个操作查询此表。根据您的存储解决方案,我将此表中的每一列都视为性能索引。随着时间的推移,该表可能具有INSERT(s)的指数反向可能性。实际上,处理这个表应该主要是一个进程内操作(RAM)。

Business2HoursMap

注意:在我的例子中,我存储&#34; Day&#34;作为位标志字段/列。这主要是由于我的需求以及C#中LINQ / Flags Enums的进步。没有什么可以阻止你将它扩展到7位字段。这两种方法在存储逻辑和查询方法上应该相对相似。

另一个注意事项:我没有在&#34上输入语义参数;每个表都需要一个PK ID列&#34;,请找到另一个论坛。

BusinessID | HoursID |一天(或者,如果你喜欢分成:BIT星期一,BIT星期二,......)


1 | 1 | 1111111(这项业务每周9-5开放)

2 | 2 | 1111110(此业务开放时间为周五9:05 - 5:01(周一=第1天)

这很容易查询的原因是我们可以很容易地确定我们之后的MOTD(每日一分钟)。如果我想知道明天下午5点什么时候开放,我会抓住所有HoursOfOperations IDS WHERE关闭&gt; = 1020.除非我正在寻找时间范围,否则Open变得无足轻重。如果您不希望在接下来的半小时内显示商家关闭,请相应调整您的收入时间(搜索下午5:30(1050),而不是下午5:00(1020)。 第二个查询自然会给我所有业务与HoursID IN(1,2,3,4,5)等。这可能会引发一个红旗,因为这种方法有局限性。但是,如果有人能够回答上面的实际排列问题,我们可能会将红旗拉下来。考虑我们只需要在等式的任何一侧进行可能的排列,无论是打开还是关闭。

考虑到我们已经缓存了第一个表格,这是一个快速的操作。第二个操作是查询这个可能很大的行表,但是我们正在搜索非常小的(SMALLINT)希望索引的列。

现在,您可能会看到代码方面的复杂性。我的目标主要是针对我的特定项目中的酒吧,因此我可以非常安全地假设我将拥有相当数量的公司,例如&#34; 11:00 AM - 2:00上午(第二天)&#34;。这确实是HoursOfOperations表和Business2HoursMap表中的两个条目。例如。从11:00 AM - 凌晨2:00开放的酒吧将有2个参考HoursOfOperations表660 - 1440(上午11:00 - 午夜)和0 - 120(午夜 - 凌晨2:00)。这些引用将反映到Business2HoursMap表中的实际天数,在我们的简单案例中为2个条目,1个条目=所有天小时参考#1,另一个全天参考#2。希望这是有道理的,这是漫长的一天。

覆盖特殊日子/假日/等等。 覆盖本质上是基于日期的,而不是基于星期几的。我认为这是一些方法试图将众所周知的圆钉推入方孔中的地方。我们需要另一张桌子。

HoursID | BusinessID |一天|月|年

1 | 2 | 1 | 1 | NULL

如果你需要像每周二这样的东西,这肯定会变得更加复杂,这家公司去钓鱼4小时&#34;。但是,这将使我们很容易做到的是允许1 - 覆盖,2 - 合理的重复覆盖。例如。如果年份为空,那么每年元旦,这个怪人酒吧的营业时间为上午9:00至下午5:00,与上述数据示例保持一致。即 - 如果设定年份,则仅适用于2013年。如果月份为空,则为每月的第一天。同样,这不仅仅通过NULL列来处理每个调度方案,但理论上,如果需要,您可以依赖于一长串绝对日期来处理任何事情。

同样,我会在滚动日的基础上缓存此表。我实际上无法在单日快照中看到此表的行非常大,至少对我的需求而言。我会首先检查这个表,因为它很好,一个覆盖,并将保存对存储端更大的Business2HoursMap表的查询。

有趣的问题。我真的很惊讶这是我第一次真正需要考虑这一点。一如既往,非常热衷于我的方法中的不同见解,方法或缺陷。

答案 6 :(得分:0)

段块更好,只需确保为用户提供一种简单的方法来设置它们。点击并拖动很好。

当你越过午夜边界时,任何其他系统(如范围)都会非常烦人。

至于如何存储它们,在C ++中,bitfields可能是最好的。在大多数其他语言中,数组可能更好(大量浪费的空间,但运行速度更快,更容易理解)。

答案 7 :(得分:0)

我现在会考虑一下这些边缘情况,因为它们会告知您是否有基本配置加上覆盖或完全静态存储的开放时间或其他。

有很多例外 - 并且定期(如下雪天,复活节,耶稣受难节等不规则假期),如果预期这是对现实的可靠表示(而不是一个好的猜测),那么你我很快就需要在架构中解决这个问题。

答案 8 :(得分:0)

这样的事情怎么样:

营业时间表

Business_id (int)
Start_Time (time)
End_Time (time)
Condition varchar/string
Open bit

'Condition'是一个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点关闭,会发生什么。您的系统也应该能够通过巧妙地分割两天之间的时间来处理它。

答案 9 :(得分:-1)

这里肯定没有必要节省内存,但可能需要干净且易于理解的代码。 “叮叮当当”不是,恕我直言,是要走的路。

我们需要一个集合容器,它可容纳任意数量的独特商品,并可快速轻松地确定商品是否为会员。设置需要小心,但在日常使用中,一行简单易懂的代码可确定您是打开还是关闭

概念: 将指数编号分配给每15分钟一次,从星期日午夜开始。

初​​始化: 打开时,将每15分钟块的索引号插入集合中。 (假设你的开放时间少于你关闭的时间。)

使用: 从上一个星期日的分钟,午夜减去有趣的时间减去15分。如果这个数字出现在集合中,那么你就是开放的。