不包括自定义期间的日期之间的差异
difference between dates excluding custom periods
早上好,
我需要一个计算特定日期之间天数的解决方案。此外,我需要排除特定日期(public 节假日和周末),这很容易,而且有很多关于如何操作的说明。
但我还需要完成一件事。对于每个人,我也有自定义假期,我需要从以前的结果中减去它们。
目前,我有两个 table。一个用于自定义假期:
+-----+----------+---------------------+---------------------+------+
| id | employee | start | end | away |
+-----+----------+---------------------+---------------------+------+
| 835 | 2.3 | 2016-12-05 00:00:00 | 2016-12-10 00:00:00 | P |
| 836 | 5.3.5.1 | 2017-01-03 00:00:00 | 2017-01-23 00:00:00 | P |
| 837 | 5.3.5.6 | 2016-12-21 00:00:00 | 2017-04-01 00:00:00 | P |
| 838 | 5.3.3.1 | 2017-01-01 00:00:00 | 2017-01-03 00:00:00 | P |
| 839 | 5.3.1.2 | 2017-01-03 00:00:00 | 2017-01-12 00:00:00 | P |
| 840 | 5.3.1.6 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | P |
| 841 | 5.1.7 | 2017-01-09 00:00:00 | 2017-01-15 00:00:00 | P |
| 842 | 2.2 | 2017-02-16 00:00:00 | 2017-02-26 00:00:00 | P |
| 843 | 2.5 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 844 | 2.5 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 845 | 2.5 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 846 | 2.4 | 2017-04-04 00:00:00 | 2017-04-08 00:00:00 | P |
+-----+----------+---------------------+---------------------+------+
12 rows in set (0.00 sec)
我在开始和结束时有日期和时间的原因是 table 实际上也有关于他们工作时间表的信息。休假时间表由 'away' 列标记为 'P'。
第二个 table 看起来像这样:
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | varchar(45) | YES | | NULL | |
| dayofweek | varchar(45) | YES | | NULL | |
| short | varchar(45) | YES | | NULL | |
| holiday | varchar(45) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
这个 table 基本上是一个日历,其中包含关于星期几的附加信息(我知道这可以用 dayofweek() 来完成,但我也需要这个专栏),'short'确定它是否是缩短的工作日(在计算小时数时很重要,因为一年中有几天工作日较短)和 'holiday' 标记 public 假期。
我想弄清楚如何通过减去 public 节假日和周末(我可以做到并且相对容易)来计算一个月内的工作日 (01.08.2017 - 31.08.2017) 以及减去自定义假期。主要问题是,对于某些人来说,一个月内可能会有不止一次缺勤。
如果您查看上面的示例,员工 2.5 的休假期从 7 月开始到 8 月结束,我只需要减去该期间 8 月的金额。员工 2.5 在八月份有另一个假期,我也需要减去这个。除此之外,这名员工还有一个从 6 月到 7 月的假期。
完美的结果应该是这样的:
+----------+-------+---------------+--------------+---------------+
| employee | month | working hours | working days | vacation days |
+----------+-------+---------------+--------------+---------------+
我能想出的唯一解决方案是创建一个名为 vacations 的新 table,其中每一天都有一列,每行显示一名员工的数据。或者反过来,员工是列,行是日期。但在我知道没有更简单的方法之前,我不想开始尝试这个想法。
再一次,我确信 mysql 中有一个简单的函数可以做到这一点,但我没弄明白。
要计算工作时间,请执行以下操作:
$to_time = strtotime("$row[2]");
$from_time = strtotime("$row[3]");
$diff = $to_time - $from_time
echo round(abs($diff) / 3600,2). " hour(s)";
$row[2] 和 $rows[3] 是您的开始日期和结束日期。他们/3600是计算小时的,你写60就可以得到分钟而不是3600。
至于工作日和休假,您可以使用 $diff 变量设置一个计数器,按天递增,休假时递减。计算您喜欢的小时数或天数,然后increment/decrement按照您喜欢的方式计算。
我整理了一下。我终于得到了我需要的东西。
一开始我改了 calendar
table:
mysql> select id,date,workday from calendar where date between '2017-06-20' and '2017-06-30';
+-----+------------+---------+
| id | date | workday |
+-----+------------+---------+
| 202 | 2017-06-20 | 1 |
| 203 | 2017-06-21 | 1 |
| 204 | 2017-06-22 | 0.625 |
| 205 | 2017-06-23 | Holiday |
| 206 | 2017-06-24 | Holiday |
| 207 | 2017-06-25 | NULL |
| 208 | 2017-06-26 | 1 |
| 209 | 2017-06-27 | 1 |
| 210 | 2017-06-28 | 1 |
| 211 | 2017-06-29 | 1 |
| 212 | 2017-06-30 | 1 |
+-----+------------+---------+
11 rows in set (0.00 sec)
1 在workday
列表示这是一个普通的工作日,NULL 表示它不是(周末),0.625 是缩短的工作日(5/8=0,625)。缩短的工作日是 5 小时。这基本上意味着如果我对 workday
列求和并将其乘以普通工作日的长度,我将根据 select 时间段之间的规律得到正常工作时间。
为此,目前我只是设置了一些变量,这只是一项正在进行的工作:
set @START='2016-12-01';
set @END='2016-12-31';
set @WORKDAY=8;
set @norm=(select sum(workday)*@workday from calendar where date between @start and @end);
所以变量 @START
和 @END
给出了我感兴趣的时间段。 @NORM
将给我正常的工作时间,如果一个人没有休假或病假@START
和 @END
.
我向 schedule
添加了一些通用数据:
mysql> select id,position,start,end,away from schedule where away='P';
+-----+----------+---------------------+---------------------+------+
| id | position | start | end | away |
+-----+----------+---------------------+---------------------+------+
| 835 | 2.3 | 2016-12-05 00:00:00 | 2016-12-10 00:00:00 | P |
| 836 | 5.3.5.1 | 2017-01-03 00:00:00 | 2017-01-23 00:00:00 | P |
| 837 | 5.3.5.6 | 2016-12-21 00:00:00 | 2017-04-01 00:00:00 | P |
| 838 | 5.3.3.1 | 2017-01-01 00:00:00 | 2017-01-03 00:00:00 | P |
| 839 | 5.3.1.2 | 2017-01-03 00:00:00 | 2017-01-12 00:00:00 | P |
| 840 | 5.3.1.6 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | P |
| 841 | 5.1.7 | 2017-01-09 00:00:00 | 2017-01-15 00:00:00 | P |
| 842 | 2.2 | 2017-02-16 00:00:00 | 2017-02-26 00:00:00 | P |
| 843 | 2.5 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 844 | 2.5 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 845 | 2.5 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 846 | 2.4 | 2017-04-04 00:00:00 | 2017-04-08 00:00:00 | P |
| 847 | 2.3 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 848 | 2.3 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 849 | 2.3 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 850 | 2.5 | 2017-08-29 00:00:00 | 2017-09-15 00:00:00 | P |
| 851 | 2.3 | 2017-08-29 00:00:00 | 2017-09-15 00:00:00 | P |
| 852 | 2.1 | 2016-11-15 00:00:00 | 2016-12-20 00:00:00 | P |
| 853 | 2.2 | 2016-11-10 00:00:00 | 2017-01-15 00:00:00 | P |
+-----+----------+---------------------+---------------------+------+
19 rows in set (0.00 sec)
为了获取每个员工具体工作的信息,我使用以下 select:
SELECT position,@NORM AS normhrs,@NORM - (SUM(vac_workday))*@WORKDAY AS wrkhrs
FROM
(
SELECT position,holiday_start,holiday_end,
(SELECT SUM(workday) FROM calendar WHERE date BETWEEN holiday_start AND holiday_end) AS vac_workday
FROM
(
SELECT position,
DATE_FORMAT(CASE WHEN start<=@START THEN @START ELSE start END,'%Y-%m-%d') AS 'holiday_start',
DATE_FORMAT(CASE WHEN end>=@END THEN @END ELSE end END,'%Y-%m-%d') AS 'holiday_end'
FROM schedule WHERE away IS NOT NULL AND DATE_FORMAT(CASE WHEN start<=@START AND end>=@START THEN @START
WHEN start>=@START AND start<=@END THEN start
ELSE NULL end,'%Y-%m')=DATE_FORMAT(@START,'%Y-%m')
)
AS outertable
)
AS outertable2 GROUP BY position;
这给了我输出。只有 @START
到 @END
有假期的人。如果此人不在输出中,则适用正常时间:
+----------+---------+--------+
| position | normhrs | wrkhrs |
+----------+---------+--------+
| 2.1 | 165 | 53 |
| 2.2 | 165 | 0 |
| 2.3 | 165 | 133 |
| 5.3.5.6 | 165 | 120 |
+----------+---------+--------+
4 rows in set, 6 warnings (0.00 sec)
这是我要找的输出。我仍然需要想出 SELECT 来总结实际工作时间,但很容易不把它放在这里。
抱歉,我知道我已经解释过了一些东西,但我完全是菜鸟,找到了类似的,相当详尽的答案,非常有帮助。
早上好,
我需要一个计算特定日期之间天数的解决方案。此外,我需要排除特定日期(public 节假日和周末),这很容易,而且有很多关于如何操作的说明。
但我还需要完成一件事。对于每个人,我也有自定义假期,我需要从以前的结果中减去它们。
目前,我有两个 table。一个用于自定义假期:
+-----+----------+---------------------+---------------------+------+
| id | employee | start | end | away |
+-----+----------+---------------------+---------------------+------+
| 835 | 2.3 | 2016-12-05 00:00:00 | 2016-12-10 00:00:00 | P |
| 836 | 5.3.5.1 | 2017-01-03 00:00:00 | 2017-01-23 00:00:00 | P |
| 837 | 5.3.5.6 | 2016-12-21 00:00:00 | 2017-04-01 00:00:00 | P |
| 838 | 5.3.3.1 | 2017-01-01 00:00:00 | 2017-01-03 00:00:00 | P |
| 839 | 5.3.1.2 | 2017-01-03 00:00:00 | 2017-01-12 00:00:00 | P |
| 840 | 5.3.1.6 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | P |
| 841 | 5.1.7 | 2017-01-09 00:00:00 | 2017-01-15 00:00:00 | P |
| 842 | 2.2 | 2017-02-16 00:00:00 | 2017-02-26 00:00:00 | P |
| 843 | 2.5 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 844 | 2.5 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 845 | 2.5 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 846 | 2.4 | 2017-04-04 00:00:00 | 2017-04-08 00:00:00 | P |
+-----+----------+---------------------+---------------------+------+
12 rows in set (0.00 sec)
我在开始和结束时有日期和时间的原因是 table 实际上也有关于他们工作时间表的信息。休假时间表由 'away' 列标记为 'P'。
第二个 table 看起来像这样:
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | varchar(45) | YES | | NULL | |
| dayofweek | varchar(45) | YES | | NULL | |
| short | varchar(45) | YES | | NULL | |
| holiday | varchar(45) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
这个 table 基本上是一个日历,其中包含关于星期几的附加信息(我知道这可以用 dayofweek() 来完成,但我也需要这个专栏),'short'确定它是否是缩短的工作日(在计算小时数时很重要,因为一年中有几天工作日较短)和 'holiday' 标记 public 假期。
我想弄清楚如何通过减去 public 节假日和周末(我可以做到并且相对容易)来计算一个月内的工作日 (01.08.2017 - 31.08.2017) 以及减去自定义假期。主要问题是,对于某些人来说,一个月内可能会有不止一次缺勤。
如果您查看上面的示例,员工 2.5 的休假期从 7 月开始到 8 月结束,我只需要减去该期间 8 月的金额。员工 2.5 在八月份有另一个假期,我也需要减去这个。除此之外,这名员工还有一个从 6 月到 7 月的假期。
完美的结果应该是这样的:
+----------+-------+---------------+--------------+---------------+
| employee | month | working hours | working days | vacation days |
+----------+-------+---------------+--------------+---------------+
我能想出的唯一解决方案是创建一个名为 vacations 的新 table,其中每一天都有一列,每行显示一名员工的数据。或者反过来,员工是列,行是日期。但在我知道没有更简单的方法之前,我不想开始尝试这个想法。
再一次,我确信 mysql 中有一个简单的函数可以做到这一点,但我没弄明白。
要计算工作时间,请执行以下操作:
$to_time = strtotime("$row[2]");
$from_time = strtotime("$row[3]");
$diff = $to_time - $from_time
echo round(abs($diff) / 3600,2). " hour(s)";
$row[2] 和 $rows[3] 是您的开始日期和结束日期。他们/3600是计算小时的,你写60就可以得到分钟而不是3600。
至于工作日和休假,您可以使用 $diff 变量设置一个计数器,按天递增,休假时递减。计算您喜欢的小时数或天数,然后increment/decrement按照您喜欢的方式计算。
我整理了一下。我终于得到了我需要的东西。
一开始我改了 calendar
table:
mysql> select id,date,workday from calendar where date between '2017-06-20' and '2017-06-30';
+-----+------------+---------+
| id | date | workday |
+-----+------------+---------+
| 202 | 2017-06-20 | 1 |
| 203 | 2017-06-21 | 1 |
| 204 | 2017-06-22 | 0.625 |
| 205 | 2017-06-23 | Holiday |
| 206 | 2017-06-24 | Holiday |
| 207 | 2017-06-25 | NULL |
| 208 | 2017-06-26 | 1 |
| 209 | 2017-06-27 | 1 |
| 210 | 2017-06-28 | 1 |
| 211 | 2017-06-29 | 1 |
| 212 | 2017-06-30 | 1 |
+-----+------------+---------+
11 rows in set (0.00 sec)
1 在workday
列表示这是一个普通的工作日,NULL 表示它不是(周末),0.625 是缩短的工作日(5/8=0,625)。缩短的工作日是 5 小时。这基本上意味着如果我对 workday
列求和并将其乘以普通工作日的长度,我将根据 select 时间段之间的规律得到正常工作时间。
为此,目前我只是设置了一些变量,这只是一项正在进行的工作:
set @START='2016-12-01';
set @END='2016-12-31';
set @WORKDAY=8;
set @norm=(select sum(workday)*@workday from calendar where date between @start and @end);
所以变量 @START
和 @END
给出了我感兴趣的时间段。 @NORM
将给我正常的工作时间,如果一个人没有休假或病假@START
和 @END
.
我向 schedule
添加了一些通用数据:
mysql> select id,position,start,end,away from schedule where away='P';
+-----+----------+---------------------+---------------------+------+
| id | position | start | end | away |
+-----+----------+---------------------+---------------------+------+
| 835 | 2.3 | 2016-12-05 00:00:00 | 2016-12-10 00:00:00 | P |
| 836 | 5.3.5.1 | 2017-01-03 00:00:00 | 2017-01-23 00:00:00 | P |
| 837 | 5.3.5.6 | 2016-12-21 00:00:00 | 2017-04-01 00:00:00 | P |
| 838 | 5.3.3.1 | 2017-01-01 00:00:00 | 2017-01-03 00:00:00 | P |
| 839 | 5.3.1.2 | 2017-01-03 00:00:00 | 2017-01-12 00:00:00 | P |
| 840 | 5.3.1.6 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | P |
| 841 | 5.1.7 | 2017-01-09 00:00:00 | 2017-01-15 00:00:00 | P |
| 842 | 2.2 | 2017-02-16 00:00:00 | 2017-02-26 00:00:00 | P |
| 843 | 2.5 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 844 | 2.5 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 845 | 2.5 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 846 | 2.4 | 2017-04-04 00:00:00 | 2017-04-08 00:00:00 | P |
| 847 | 2.3 | 2017-07-31 00:00:00 | 2017-08-06 00:00:00 | P |
| 848 | 2.3 | 2017-08-21 00:00:00 | 2017-08-27 00:00:00 | P |
| 849 | 2.3 | 2017-06-26 00:00:00 | 2017-07-09 00:00:00 | P |
| 850 | 2.5 | 2017-08-29 00:00:00 | 2017-09-15 00:00:00 | P |
| 851 | 2.3 | 2017-08-29 00:00:00 | 2017-09-15 00:00:00 | P |
| 852 | 2.1 | 2016-11-15 00:00:00 | 2016-12-20 00:00:00 | P |
| 853 | 2.2 | 2016-11-10 00:00:00 | 2017-01-15 00:00:00 | P |
+-----+----------+---------------------+---------------------+------+
19 rows in set (0.00 sec)
为了获取每个员工具体工作的信息,我使用以下 select:
SELECT position,@NORM AS normhrs,@NORM - (SUM(vac_workday))*@WORKDAY AS wrkhrs
FROM
(
SELECT position,holiday_start,holiday_end,
(SELECT SUM(workday) FROM calendar WHERE date BETWEEN holiday_start AND holiday_end) AS vac_workday
FROM
(
SELECT position,
DATE_FORMAT(CASE WHEN start<=@START THEN @START ELSE start END,'%Y-%m-%d') AS 'holiday_start',
DATE_FORMAT(CASE WHEN end>=@END THEN @END ELSE end END,'%Y-%m-%d') AS 'holiday_end'
FROM schedule WHERE away IS NOT NULL AND DATE_FORMAT(CASE WHEN start<=@START AND end>=@START THEN @START
WHEN start>=@START AND start<=@END THEN start
ELSE NULL end,'%Y-%m')=DATE_FORMAT(@START,'%Y-%m')
)
AS outertable
)
AS outertable2 GROUP BY position;
这给了我输出。只有 @START
到 @END
有假期的人。如果此人不在输出中,则适用正常时间:
+----------+---------+--------+
| position | normhrs | wrkhrs |
+----------+---------+--------+
| 2.1 | 165 | 53 |
| 2.2 | 165 | 0 |
| 2.3 | 165 | 133 |
| 5.3.5.6 | 165 | 120 |
+----------+---------+--------+
4 rows in set, 6 warnings (0.00 sec)
这是我要找的输出。我仍然需要想出 SELECT 来总结实际工作时间,但很容易不把它放在这里。
抱歉,我知道我已经解释过了一些东西,但我完全是菜鸟,找到了类似的,相当详尽的答案,非常有帮助。