计算 PostgreSQL 中 2 个日期之间的工作时间
我正在使用 Postgres (PL/pgSQL) 开发一种算法,我需要计算 2 个时间戳之间的工作小时数,考虑到周末不工作,其余时间只计算上午 8 点到下午 15 点。
示例:
-
从 12 月 3 日下午 14 点到 12 月 4 日上午 9 点应算 2 小时:
<前><代码>第三个 = 1,第四个 = 1 -
从12月3日下午15点到12月7日上午8点应算8小时:
<前><代码>第 3 个 = 0、第 4 个 = 8、第 5 个 = 0、第 6 个 = 0、第 7 个 = 0
最好也考虑一下小时分数。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
根据您的问题,工作时间为:周一至周五,08:00–15:00。
舍入结果
仅针对两个给定时间戳,
以1 小时为单位进行操作。分数被忽略,因此不精确而是简单:
函数
generate_series()
如果末尾大于开头,则生成一行,并为每个 生成另一行完整的给定间隔(1 小时)。这个世界计数每个进入的小时。要忽略小数小时,请从末尾减去 1 小时。并且不要计算 14:00 之前开始的时间。使用字段模式
ISODOW
而不是DOW
来表示EXTRACT()
来简化表达式。周日返回7
而不是0
。简单(而且非常便宜)转换为
时间
可以轻松识别符合条件的时间。一小时的小数部分将被忽略,即使间隔开始和结束时的小数部分加起来可达一小时或更长。
对于整个表
查询:
db<>fiddle 此处
旧sqlfiddle
更精确
要获得更精确,您可以可以使用更小的时间单位。以 5 分钟切片为例:
单位越小,成本就越高。
Postgres 9.3+ 中使用
LATERAL
进行清理与新的 Postgres 9.3中的
LATERAL
功能,上面的查询可以写成:1小时精度:
5分钟精度:
这有一个额外的优势与上述版本一样,包含零工作时间的间隔不会从结果中排除。
有关
横向
的更多信息:精确结果
Postgres 8.4+
或者您分别处理时间范围的开始和结束以获得 精确到微秒的结果。使查询更加复杂,但更便宜和准确:
db<>fiddle 此处< /a>
旧的 sqlfiddle
Postgres 9.2+ 与
tsrange
新的范围类型为 <结合交集运算符精确结果 code>*:
适用于仅跨越一天的时间范围的简单函数:
如果您的范围从不跨越多天,这就是您所需要的。
否则,使用此包装函数来处理任何间隔:
调用:
db<>fiddle 此处
旧sqlfiddle
According to your question working hours are: Mo–Fr, 08:00–15:00.
Rounded results
For just two given timestamps
Operating on units of 1 hour. Fractions are ignored, therefore not precise but simple:
The function
generate_series()
generates one row if the end is greater than the start and another row for every full given interval (1 hour). This wold count every hour entered into. To ignore fractional hours, subtract 1 hour from the end. And don't count hours starting before 14:00.Use the field pattern
ISODOW
instead ofDOW
forEXTRACT()
to simplify expressions. Returns7
instead of0
for Sundays.A simple (and very cheap) cast to
time
makes it easy to identify qualifying hours.Fractions of an hour are ignored, even if fractions at begin and end of the interval would add up to an hour or more.
For a whole table
Query:
db<>fiddle here
Old sqlfiddle
More precision
To get more precision you can use smaller time units. 5-minute slices for instance:
The smaller the unit the higher the cost.
Cleaner with
LATERAL
in Postgres 9.3+In combination with the new
LATERAL
feature in Postgres 9.3, the above query can then be written as:1-hour precision:
5-minute precision:
This has the additional advantage that intervals containing zero working hours are not excluded from the result like in the above versions.
More about
LATERAL
:Exact results
Postgres 8.4+
Or you deal with start and end of the time frame separately to get exact results to the microsecond. Makes the query more complex, but cheaper and exact:
db<>fiddle here
Old sqlfiddle
Postgres 9.2+ with
tsrange
The new range types offer a more elegant solution for exact results in combination with the intersection operator
*
:Simple function for time ranges spanning only one day:
If your ranges never span multiple days, that's all you need.
Else, use this wrapper function to deal with any interval:
Call:
db<>fiddle here
Old sqlfiddle
怎么样:创建一个 24*7 行的小表,一周每小时一行。
同样,为其他每一天添加 24 行。您给出的年份或月份并不重要,稍后您就会看到。您只需要代表一周中的所有 7 天。
How about this: create a small table with 24*7 rows, one row for each hour in a week.
Likewise add 24 rows for each of the other days. It doesn't matter what year or month you give, as you'll see in a moment. You just need to represent all seven days of the week.
以下函数将获取
的输入
当天的工作开始时间
当天的工作结束时间
开始时间
结束时间
这将仅给出开始日期时间和结束日期时间之间的工作时间(以秒为单位)的差异
This following functions will take the input for the
working start time of the day
working end time of the day
start time
end time
This will give the difference of only the work hours in seconds between the start and end datetime