处理时间和午夜后的事项

9

你如何在PHP/MySQL中处理时间和午夜之后的情况?

使用INT存储分钟数还是使用TIME类型字段?

考虑以下SQL查询:

SELECT * FROM opening_hours  
        WHERE week_day = WEEKDAY(NOW()) + 1 
              AND open_hour =< date_format(now(),'%H:%i') 
              AND close_hour >= date_format(now(),'%H:%i')

open_hour / close_hour 字段是 TIME 类型的字段。

假设开门时间为 "18:00",关门时间为 "02:00",当前时间为 "22:41"。我们有一条单独的数据库记录用于关闭时间(因为它在午夜后),但我们永远不会在结果中得到它,因为关闭时间 "02:00" 不大于当前时间 "22:41"。

此外,如果当前时间为 "01:00",我们将得到下一天的值,因为星期几不匹配。

那么解决方案是什么呢?

您更愿意将这些值存储为 INT(分钟),以便 PHP 能够直接处理这些值,而无需进行任何转换吗?

例如...

当前时间:

// w = Day of the week, H = 24-hour format, i = Minutes
$timearr = explode(':',date("w:H:i"));
$currenttime = ($timearr[0]) * 1440 + $timearr[1] * 60 + $timearr[2] 

在数据库中,存储了以分钟为单位的开放/关闭时间值。
现在假设当前时间是“周日01:00”(一周的第一天),执行上述转换后,该值为60;而上个星期的开放/关闭时间(星期六)设置为“17:00”和“02:00”(实际上是星期日),存储在数据库中的值为9660和10200(星期六,26:00)。在这种情况下,上述查询将找不到我们需要的记录(星期六,17:00,02:00),因为我们可能没有任何开放时间小于“02:00”(120)。为了解决这个问题,我们将“星期日01:00”转换为“星期六25:00”,通过将7*1440(整个星期)添加到$currenttime中,结果为10140。然后进行如下数据库查询:
SELECT open_time,clos_time FROM open_hours 
    WHERE (open_time <= $currenttime 
         AND close_time >= $currenttime)
         OR (open_time <= $currenttime +10080
         AND close_time >= $currenttime + 10080);

还有什么替代方案更加简洁吗?

也许可以将日期与时间一起存储?午夜后的时间会变成明天的时间。此外,请使用DATETIME格式,而不是INT或其他格式。 - Madara's Ghost
不,我不能使用DATETIME,因为我不打算使用日期。商店每天都营业,我不想为整个年份添加日期! - I'll-Be-Back
https://dev59.com/9V3Va4cB1Zd3GeqPBIA9 - Richard EB
3个回答

2
SELECT open_time,close_time FROM open_hours 
    WHERE
         (open_time <= close_time AND
         open_time <= $currenttime AND
         close_time >= $currenttime)
         OR
         (open_time >= close_time AND
         ($currenttime <= close_time OR
         $currenttime >= open_time))

所以我在这里做的是,如果开放时间大于关闭时间,则必须跨越午夜,在这种情况下,我会检查当前计时器是否大于开放时间或小于关闭时间,以确保它落在我们的时间范围内。

开放时间 ------ 午夜 ----- 关闭时间

如果开放时间小于关闭时间,则我们知道午夜不会在两者之间。因此,我们可以像正常一样进行检查。


啊哈,那么在这种情况下,您更喜欢将这些值存储为INT(分钟)? - I'll-Be-Back
这取决于你想要什么。我知道日期在这种情况下不相关,所以我认为datetime不是最好的选择。我认为MySql中有一个时间类型http://dev.mysql.com/doc/refman/5.0/en/time.html,这将是理想的选择。 - Zoidberg

2

存储分钟(int(4)unsigned)是正确的方式。
但是,与其存储星期几+开放小时、关闭小时(带偏移量),
你应该存储自周一午夜以来的分钟数:

 Monday  18:00 = (1 - 1)*60 * 18 = 1080
 Tuesday 02:00 = (2 - 1)*60 * 24 + (2 * 60) = 1560
 ...
 // please take note shop could have different operating hour for each day

所以,当前时间是星期二凌晨1:30,即:

 // mysql expression
 $expr = (weekday(current_timestamp)+1) * 1440 + (hour(current_timestamp)*60) + minute(current_timestamp)

SQL:

 select ... 
 from opening_hours
 where
 open_time  >= $expr and
 close_time <= $expr;

我不理解这部分:(1 - 1)(2 - 1)?这是什么? - I'll-Be-Back
1 = 周一为起始日,周一 = 0,周二 = 1,...,周日 = 7(表示一周从周一开始)。 - ajreal
如果你问我,这似乎是一层不必要的复杂性。在这之前,我会将时间以24小时制的字符串形式存储(例如0800、1200、2140等)。比较仍然有效,并且您可以轻松地查看数字并理解正在发生的事情。 - Zoidberg
我认为你应该重新阅读问题。我已经读了两遍,我认为我对他的问题有一个相当牢固的理解。他使用一周中的天数来说明他的问题,它们实际上并不是他期望解决方案的一部分。 - Zoidberg
考虑到商店每天的营业时间可能不同,那么如何不将日期作为考虑因素呢? - ajreal
显示剩余2条评论

0

我不知道你想做什么,但在我看来,使用Unix时间戳始终是正确的答案。它更容易计算,并且无论时区如何,它总是正确的。

也许你应该研究一下这个。


时间戳仍然存储日期信息,但在这种情况下并不需要,因为开盘和收盘时间每天都会重复出现。 - Zoidberg
是的,但你可以提取正确的时间:echo date("g:i a",$timestamp); - Adam Fowler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接