计算介于预定义日期范围之间的天数
Posted
技术标签:
【中文标题】计算介于预定义日期范围之间的天数【英文标题】:Computing number of days which fall between predefined date ranges 【发布时间】:2011-02-23 17:50:01 【问题描述】:这是一个复杂的情况。我有一个预订系统,可以预订房间。
问题是房间的价格不是作为单一值存储的,而是基于时间段的。就像一个房间在 9 月到 12 月之间可以有一个每日房价,从 3 月到 8 月可以有不同的房价,而在其他情况下有一个基本房价。
费率表是这样的:
ROOMID | RATE | PERIOD_START | PERIOD_END
假设 3 月 1 日至 3 月 31 日期间的房间价格为 20 美元/天,4 月 15 日至 5 月 30 日同一房间的价格为 30 美元,但价格是 15 美元的统一价格/天。
如果此房间由一位客户在 3 月 15 日至 5 月 10 日期间预订,则总费用为:
15th March - 31st march charged at 20 Dollars/day = 16x20
1st April - 14th April charged at 15 Dollars/day = 14x15
15th April - 10th May charged at 30 Dollars/day = 25x30
现在我如何在代码中计算这个值,如果有的话,我需要根据费率周期计算天数,否则为它们使用基本费率。它很复杂,但就是这样。我正在使用 php mysql
【问题讨论】:
SQL To check if a set of dates fall within a specified range of datesOr maybe this的可能重复 所以问题是要预订的某些日子可能在不同的价格/日期范围内?那么是在 3 月 31 日之前 3 天,然后在 4 月 1 日之后再过两天? @jonah - 是的,正如你所说的那样 @Linus - 该项目是相同的,但它的情况不同,即它涉及根据不同时期的不同费率计算成本,其他问题都没有解决这个问题 【参考方案1】:这是一个可能的解决算法:
-
查找与预订期有非空交叉点的所有费率期
对于 (1) 中找到的每个费率期,计算其与预订期相交的天数,然后乘以该期的费率
剩余天数(即以天为单位的预订天数减去 (2) 中找到的所有天数的总和是您的基本费率天数
关于 (1),为了找出哪些费率周期与预订周期相交,请注意两个区间 (A,B)
和 (C,D)
有一个空的交叉点 iff D < A or C > B
,所以你可以否定这个条件。应该看起来像:
SELECT * FROM rates
WHERE NOT (booking_end < period_start OR
booking_start > period_end)
Re (2),你只需要找到max(booking_start, period_start)
和min(booking_end, period_end)
之间的天数,包括在内。我确信有一些实用程序可以处理日期,但在最坏的情况下,你可以循环遍历它。
抱歉,我不是编写实际代码的 SQL/php 向导... :)
【讨论】:
【参考方案2】:一种可能的解决方案是使用一个名为 price_periods 的表,其中包含开始日期、结束日期和价格以及对房间的引用。
所以 SQL 表看起来像这样。
PRICE_PERIODS
PPID | ROOM_ID | PP_START_DATE | PP_END_DATE | PP_PRICE
-------------------------------------------------------
1 2 09-20 10-20 15
2 2 10-21 11-20 20
然后您只需计算预订的截止日期,因此假设 A 想从 10-11 到 10-25 租一个房间,他必须支付 ID 为 1 的 PRICE_PERIOD,直到 PP_END_DATE 发生然后支付 ID 为 2 的 PRICE_PERIOD,直到预订结束。所以问题是您可能随时都有两个以上的约会对象。
我想您的预订表看起来像这样。
预订
B_ID | ROOM_ID | USER_ID | START_DATE | END_DATE
------------------------------------------------
1 2 4 10-11 10-25
您必须进行计算,但有一个开始可能会奏效。
【讨论】:
【参考方案3】:这里只是半认真的回答。
如果你想要一个 SQL 查询,你可以这样做:
SELECT SUM(IF(ISNULL(r.rate), 10, r.rate))
FROM days AS d
LEFT JOIN rates AS r ON d.d BETWEEN r.start AND r.end
WHERE d.d BETWEEN '2011-03-15' and '2011-05-10';
诀窍是您需要一个名为“days”的表,它有一个日期字段 d。预先填充该表以包括从现在到永恒的每一天。通过脚本很容易做到;您只需要在其中保留未来的可预订日期。
请注意,您必须谨慎选择开始日期和结束日期。例如,如果您在 3 月 31 日至 4 月 1 日之间预订房间,这究竟意味着什么?
是一天 20 美元,一天 10 美元吗?还是只有一天 20 美元?还是一天 10 美元?
它本身并不会真正影响这个答案,但它确实会影响您如何构建费率表以及您使用哪一天作为开始和停止。
此外,此版本假定费率字段使用完整的 YYYY-MM-DD 格式。这不是绝对要求,但如果只是 MM-DD,那么你必须稍微修改一下联接。
就我个人而言,我不会这样做。相反,我只是使用 DateInterval
类在 PHP 代码中循环遍历这些天并以这种方式查询价格。
【讨论】:
【参考方案4】:试试这个。
这会遍历预订期间的每一天,从表中找到合适的费率,然后将其添加到总数中。
$Day="2011-03-15";
$End="2011-05-10";
$Periods=array(); // Filled with the Mysql rows - mysql_fetch_assoc()
$Total=0;
编辑
更优化。
foreach($Periods as $Period)
if($Day>=$Period['PERIOD_START']&&$Day<=$Period['PERIOD_END'])
while($Day<=$End&&$Day<=$Period['PERIOD_END'])
$Total+=$Period['RATE'];
$Day=date('Y-m-d',strtotime("$Day +1 day"));
【讨论】:
如果您想对此进行优化,您实际上并不需要在每次迭代中逐步完成每个周期。只需保持周期排序,当您超过当前周期时,切换到下一个周期。如果$day < $period->start
,您会知道您是否在两个时期之间(10 美元)。
通过在顶部添加 Periods 循环对其进行了更多优化。这减少了不必要的循环。【参考方案5】:
在 PHP 中,您可以使用 DateTime 到 calculate the difference 两个日期之间的间隔。
【讨论】:
以上是关于计算介于预定义日期范围之间的天数的主要内容,如果未能解决你的问题,请参考以下文章