不包括自定义期间的日期之间的差异

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 来总结实际工作时间,但很容易不把它放在这里。

抱歉,我知道我已经解释过了一些东西,但我完全是菜鸟,找到了类似的,相当详尽的答案,非常有帮助。