将时间范围分割成多个部分
第一个问题。温柔一点。
我正在开发一种软件,可以跟踪技术人员在任务上花费的时间。该软件需要得到增强,以根据一周中的某一天和一天中的时间识别不同的计费费率乘数。 (例如,“工作日下午 5 点半后的时间。”)
使用该软件的技术人员只需记录日期、他的开始时间和他的停止时间(以小时和分钟为单位)。该软件预计将在速率乘数变化时将时间输入分解为多个部分。单次输入不允许跨越多天。
这是费率表的部分样本。显然,第一级数组的键是星期几。第二级数组键代表一天中新乘数启动的时间,并一直运行到数组中的下一个连续条目。数组值是该时间范围的乘数。
[rateTable] => Array
(
[Monday] => Array
(
[00:00:00] => 1.5
[08:00:00] => 1
[17:00:00] => 1.5
[23:59:59] => 1
)
[Tuesday] => Array
(
[00:00:00] => 1.5
[08:00:00] => 1
[17:00:00] => 1.5
[23:59:59] => 1
)
...
)
用简单的英语来说,这代表从午夜到上午 8 点的半时费率、晚上 8 点到下午 5 点的正常费率以及从下午 5 点到晚上 11:59 的半时费率。这些中断发生的时间可以是任意的,精确到秒,并且每天可以有任意数量的中断。 (此格式完全可以协商,但我的目标是使其尽可能易于人类阅读。)
例如:周一 15:00:00(下午 3 点)记录的时间条目到 21:00:00(晚上 9 点)期间包括按 1 倍计费的 2 小时和按 1.5 倍计费的 4 小时。单次输入也可以跨越多个中断。使用上面的示例速率表,从上午 6 点到晚上 9 点的时间条目将具有 3 个子范围:上午 6-8 点 @ 1.5x、上午 8 点-下午 5 点 @ 1x 和下午 5-9 点 @ 1.5x。相比之下,时间条目也可能仅在 08:15:00 到 08:30:00 之间,并且完全包含在单个乘数的范围内。
我确实可以使用一些帮助来编码一些 PHP(或者至少设计一种算法),这些 PHP 可以需要一周中的一天、开始时间和停止时间,并解析为所需的子部分。理想的情况是输出是一个由(开始、停止、乘数)三元组的多个条目组成的数组。对于上面的示例,输出将是:
[output] => Array
(
[0] => Array
(
[start] => 15:00:00
[stop] => 17:00:00
[multiplier] => 1
)
[1] => Array
(
[start] => 17:00:00
[stop] => 21:00:00
[multiplier] => 1.5
)
)
我只是无法理解将单个(开始,停止)分成(可能)多个子部分的逻辑。
First question. Be gentle.
I'm working on software that tracks technicians' time spent working on tasks. The software needs to be enhanced to recognize different billable rate multipliers based on the day of the week and the time of day. (For example, "Time and a half after 5 PM on weekdays.")
The tech using the software is only required to log the date, his start time and his stop time (in hours and minutes). The software is expected to break the time entry into parts at the boundaries of when the rate multipliers change. A single time entry is not permitted to span multiple days.
Here is a partial sample of the rate table. The first-level array keys are the days of the week, obviously. The second-level array keys represent the time of the day when the new multiplier kicks in, and runs until the next sequential entry in the array. The array values are the multiplier for that time range.
[rateTable] => Array
(
[Monday] => Array
(
[00:00:00] => 1.5
[08:00:00] => 1
[17:00:00] => 1.5
[23:59:59] => 1
)
[Tuesday] => Array
(
[00:00:00] => 1.5
[08:00:00] => 1
[17:00:00] => 1.5
[23:59:59] => 1
)
...
)
In plain English, this represents a time-and-a-half rate from midnight to 8 am, regular rate from 8 to 5 pm, and time-and-a-half again from 5 till 11:59 pm. The time that these breaks occur may be arbitrary to the second and there can be an arbitrary number of them for each day. (This format is entirely negotiable, but my goal is to make it as easily human-readable as possible.)
As an example: a time entry logged on Monday from 15:00:00 (3 PM) to 21:00:00 (9 PM) would consist of 2 hours billed at 1x and 4 hours billed at 1.5x. It is also possible for a single time entry to span multiple breaks. Using the example rateTable above, a time entry from 6 AM to 9 PM would have 3 sub-ranges from 6-8 AM @ 1.5x, 8AM-5PM @ 1x, and 5-9 PM @ 1.5x. By contrast, it's also possible that a time entry may only be from 08:15:00 to 08:30:00 and be entirely encompassed in the range of a single multiplier.
I could really use some help coding up some PHP (or at least devising an algorithm) that can take a day of the week, a start time and a stop time and parse into into the required subparts. It would be ideal to have the output be an array that consists of multiple entries for a (start,stop,multiplier) triplet. For the above example, the output would be:
[output] => Array
(
[0] => Array
(
[start] => 15:00:00
[stop] => 17:00:00
[multiplier] => 1
)
[1] => Array
(
[start] => 17:00:00
[stop] => 21:00:00
[multiplier] => 1.5
)
)
I just plain can't wrap my head around the logic of splitting a single (start,stop) into (potentially) multiple subparts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我将使用不同的方法,并且我将基于几个考虑因素更改rateTable 表示形式。
最后但并非最不重要的一点是,我个人的经验让我说,如果你不能全神贯注于算法,那么你的同事很可能会遇到同样的困难(即使你成功并解决了问题),并且代码也会是 bug 的主要来源。如果您找到一种更简单、更有效的解决方案,将会节省时间、金钱并减少麻烦。即使解决方案不是那么有效,也许也会有所收获。
至少您需要一个函数将原始格式转换为新格式。
是的,您可以即时进行转换,
但如果您关心一点性能......
I would use a different approach, and I will change the rateTable representation based of a couple of considerations.
Last but not least, my personal experience let me say that if you can't wrap your head on an algorithm it is likely that your co-workers will have the same difficulties (even if you succeed and resolve the issues) and the code will be a primary source of bug. If you find a simpler and efficient solution it will be a gain of time, money and headaches. Maybe it will be a gain even if the solution is not so efficient.
At the very least you need a function to convert the original format to the new one.
And yes, you could do the conversion on the fly with
but if you care a bit of performances...
这是我的方法,
我将所有内容都转换为秒,以使其更容易。
这是按秒索引的速率表。星期一只有 3 个时间段
它使用此函数将 hh:mm:ss 转换为秒
这是返回费率表的函数
以下是使用它的方法
返回
基本上,代码循环遍历费率表并查找从给定的时隙属于每个速率。
Here's my method
I converted everything to seconds to make it a lot easier.
Here's the rate table indexed by seconds. Theres only 3 time slots for monday
It uses this function to convert hh:mm:ss to seconds
This is the function that returns a rate table
Here's how you use it
returns
Basically the code loops over the rate table and finds how many seconds from the given time slot belong to each rate.
我会建议类似的东西
在内部将所有时间转换为秒可能会更容易,以使天/小时/分钟计算更容易处理。
I would suggest something like
It might be easier to convert all your times to seconds internally to make the days/hours/minutes calculations easier to handle.
这基本上是@Loopo 算法的改编。
首先,如果能够使用
>
和<
比较时间就好了,所以首先我们转换所有时间(星期几 + 小时/分钟/秒) ) 到 UNIX 时间偏移量:理想情况下,这已经完成(例如,您将这些转换后的偏移量存储在数据库中,而不是原始的
xx:yy:zz D
字符串)。现在是分离器(由于缺少闭包而有一个助手):
并使用该类:
希望这会有所帮助。
This is basically an adaptation of @Loopo's algorithm.
First, it'd be nice to be able to compare times using
>
and<
, so first we convert all times (day of week + hour/minute/second) to UNIX time offsets:Ideally, this would have already been done (e.g. you store these converted offsets in the database instead of the original
xx:yy:zz D
strings).Now the splitter (with a helper due to the lack of closures):
And using the class:
Hope this helps.
Eineki 破解了该算法。我的尝试中缺少的部分是每个乘数范围内都有可用的开始时间和停止时间。我重视原始速率表中的数据密度,因此我使用了 Eineki 的 Convert() 例程的核心来获取存储在配置中的表并添加停止时间。我的代码已经自动创建(或填充)了最小速率表,保证其余代码不会阻塞或抛出警告/错误,所以我将其包括在内。我还将 bill() 和 map_shift() 压缩在一起,因为在我看来,如果没有彼此,两者就没有任何有用的目的。
谢谢大家,特别是Eineki。
Eineki cracked the algorithm. The part missing from my attempts was having the start and the stop time available in each multiplier range. I value the density of data in my original rateTable, so I used the guts of Eineki's convert() routine to take the table stored in config and add the stop times in. My code already auto-created (or filled in) a minimal rate table, guaranteeing that the rest of the code won't choke or throw warning/errors, so I included that. I also condensed bill() and map_shift() together since in my mind the two don't have any useful purpose without each other.
Thanks everyone, especially Eineki.