php计算工作日

匿名 (未验证) 提交于 2019-12-02 22:11:45

  在做政府项目时经常会遇到要就算工作日的情况,在网上找了一圈就只有一些告诉大家怎么做的没有可以拿来就用的代码(可能是没有找到),所以我就把我写出来的发出来;

  我是用thinkphp5写的,原生或其他框架可以直接复制计算节假日类;

  首先说下我是怎么做的:

  第一步

    获取节假日安排,由于考虑到人家接口的稳定性然后又没有找到对应大厂的接口,这个我就自己写了,这个我就不详细写了,后面会贴出对应的代码,直接整合就好了

    

  第二步

    我是习惯先写调用的接口,所以在接口中规定要计算的开始时间、天数,返回的格式(最后一天或中间所有的时间)

    

第三步

    调用接口由于到数据库中存的节假日安排的只有一个开始时间没有详细的放假时间,所以先处理详细的放假安排,然后考虑到如果计算天数很大的话可能会出现内存泄漏的问题,所以我就把放假时间和补班时间放在了一个数组中,减少后面的遍历

    

  第四步

    生成从指定时间到指定天数的原始数据,如:2019-10-10是开始时间,计算100天工作日的时间,就先生成一百条数据,从10月11日开始明天一条数据存到数组中

    

    

第五步

      判断原始数据中的时间是否是周六、周日或节假日,是的话就删除对应的值,重新生成,一直处理到没有周六周日和节假日为止,这样就把节假日给就算出来了

      

      

第六步

      最后就是调用get方法,把计算好的节假日数据请求出来就好了

      

https://github.com/18370800152/php-Calculate-Chinese-workday

    index.php

    

<?php
namespace app\index\controller;

use think\Controller;
use think\Db;

/**
* 节假日
*/
class Index extends Controller
{
//节假日列表
public function index()
{
$list = Db::name('festival')->select();

foreach ($list as $key => &$value)
{
$value['addtime'] = date('Y-m-d H:i:s', $value['addtime']);
}

$this->assign('list',$list);
return $this->fetch();
}

//添加
public function add()
{
if(!$this->request->isPost())
{
return $this->fetch();
}
$name = input('post.name/a', '', 'htmlspecialchars');
$num = input('post.num/a', '', 'htmlspecialchars');
$addtime = input('post.addtime/a', '', 'htmlspecialchars');
$repairTime = input('post.repairTime/a', '', 'htmlspecialchars');
$data['year'] = input('post.year/d', '', 'htmlspecialchars');

$data = array_merge($this->generalPurpose($name, $num, $addtime, $repairTime), $data);
$data['addtime'] = time();

$id = Db::name('festival')->insertGetId($data);
if($id > 0)
{
echo json_encode(['SUCCESS', $id]);
exit;
}

echo json_encode(['ERROR', '添加失败']);
exit;
}

//修改
public function data()
{
if(!$this->request->isPost())
{
$id = input('get.id/d', '', 'htmlspecialchars');

//判断id是否正确
if($id <= 0)
{
echo json_encode(['ERROR', 'id不正确']);
exit;
}
$list = Db::name('festival')->field('id,year,festival')->where('id', $id)->find();

//判断是否有数据
if(count($list) == 0)
{
echo json_encode(['ERROR', 'id不正确']);
exit;
}

$festival = json_decode($list['festival'], true);

foreach ($festival as $key => &$value)
{
$value['repair'] = implode('/', $value['repair']);
}

$this->assign('content', $list);
$this->assign('list', $festival);

return $this->fetch();
}

$name = input('post.name/a', '', 'htmlspecialchars');
$num = input('post.num/a', '', 'htmlspecialchars');
$addtime = input('post.addtime/a', '', 'htmlspecialchars');
$repairTime = input('post.repairTime/a', '', 'htmlspecialchars');
$data['year'] = input('post.year', '', 'htmlspecialchars');
$data['id'] = input('post.code', '', 'htmlspecialchars');
$type = input('post.type', '', 'htmlspecialchars');

if(!in_array($type, ['add', 'update']))
{
echo json_encode(['SUCCESS', '修改成功']);
exit;
}

$data = array_merge($this->generalPurpose($name, $num, $addtime, $repairTime), $data);

if(Db::name('festival')->update($data))
{
echo json_encode(['SUCCESS', '修改成功']);
exit;
}

echo json_encode(['ERROR', '修改失败']);
exit;
}

//通用处理数据
public function generalPurpose($name, $num, $addtime, $repairTime)
{
//清除为空的数据,只根据名称来组合数据,如果没有添加名称但添加了后面的数据就不会存
$name = array_filter($name);
$data['festival'] = [];
foreach ($name as $key => $value)
{
$fatalism = explode('/', $repairTime[$key]);
if(empty($fatalism[0]))
{
$fatalism = [];
}

$data['festival'][] = [
'name' => $name[$key],
'time' => $addtime[$key],
'fatalism' => $num[$key],
'repair' => $fatalism
];
}
$data['festival'] = json_encode($data['festival']);

return $data;
}

/**
* 获取节假日数据的接口
* @DateTime 2019-10-08T17:48:34+0800
* string $starttime 开始时间,格式:Y-m-d
* int $num 要计算工作日的天数
* string $type 要返回的类型 whole为所有工作日的时间戳 last最后那天的时间戳
* @return json
*/
public function get()
{
$starttime = trim(input('get.stime', '', 'htmlspecialchars'));
$num = trim(input('get.num', '', 'htmlspecialchars'));
$type = input('get.mode') ? trim(input('get.mode', '', 'htmlspecialchars')) : 'last';

if(empty($starttime))
{
echo json_encode(['message' => 'no', 'data' => '开始时间必须填写']);
exit;
}

if(empty($num))
{
echo json_encode(['message' => 'no', 'data' => '计算的天数必须填写']);
exit;
}

$festival = Db::name('festival')->where('year', date('Y'))->value('festival');
$festival = json_decode($festival, true);

$ret = new Holiday($num, $festival, strtotime($starttime));

echo json_encode(['message' => 'ok', 'data' => $ret->get($type)]);
}
}

Holiday.php

<?php
namespace app\index\controller;

/**
* 就算节假日
*/
class Holiday
{
private $oneDay = 86400; //一天的时间戳
private $num; //要计算的天数
private $festivalTime; //节假日
private $WorkingDay; //工作日数据
private $time; //记录从哪个时间开始生成时间数组
private $key = 0; //记录判断好的键值(防止重复计算)

/**
* 构造方法
* @author zzw
* @DateTime 2019-10-09T09:01:26+0800
* @param int $num 要就算的天数
* @param string $festime 节假日的数组
* @param int $time 开始时间
*/
function __construct($num,$festime,$time)
{
$this->num = $num;
$this->festivalTime = $festime;
$this->time = $time;

$this->foreign();
}

/**
* 对外的获取方法
* @author zzw
* @DateTime 2019-10-09T09:11:23+0800
* @param string $type 返回的类型 whole为所有时间戳 last最后的时间戳
* @return string/array
*/
public function get($type)
{
switch ($type)
{
case 'whole':
return $this->WorkingDay;

default:
return $this->WorkingDay[$this->num-1];
}
}

/**
* 遍历出从指定时间到指定要就算天数的所有原始时间戳
* @author zzw
* @DateTime 2019-10-09T09:06:39+0800
* @param string/array $time
*/
private function foreign()
{
$this->generateData();

$this->generateDolidayArr();

$this->checkMultiple();
}

/**
* 判断数组的日期天数和要获取天数是否一致
* @author zzw
* @DateTime 2019-10-09T14:01:15+0800
*/
private function checkMultiple()
{
//判断是否是休息或加班
$WorkingDayCount = count($this->WorkingDay);
for ($i = $this->key; $i < $WorkingDayCount; $i++)
{
$this->is_claim($i);
}

$this->WorkingDay = array_values($this->WorkingDay);

$this->key = count($this->WorkingDay) - 1;

//当前数据数量和指定数量是否一致
if(count($this->WorkingDay) < $this->num)
{
$this->generateData();

$this->checkMultiple();//递归判断数据
}

return;
}

/**
* 判断指定时间戳是否符合要求
* @author zzw
* @DateTime 2019-10-09T09:15:29+0800
* @param int $time 要判断的时间戳
* @return string
*/
private function is_claim($key)
{
//判断是否是周六或周日,区分出是加班或放假
$type = in_array(date('w', $this->WorkingDay[$key]), [0, 6]) ? 'repair' : 'time';


//如果不是加班就删除这条数据
if(!$this->is_overtime($this->WorkingDay[$key], $type))
{
unset($this->WorkingDay[$key]);
}
}

/**
* 判断是否是加班或放假
* @author zzw
* @DateTime 2019-10-09T14:09:41+0800
* @param int $time 要判断的时间戳
* @param string $type 判断是加班还是放假 repair:加班 time:放假
* @return boolean
*/
private function is_overtime($time, $type)
{
if(in_array(date('Y-m-d', $time), $this->festivalTime[$type]))
{
return $type == 'time' ? false : true;
}

return $type == 'time' ? true : false;
}

/**
* 生成放假数组
* @author zzw
* @DateTime 2019-10-09T14:55:51+0800
*/
private function generateDolidayArr()
{
foreach ($this->festivalTime as $key => $value)
{
$time = strtotime($value['time']);

for ($i = 1; $i <= $value['fatalism']; $i++)
{
$data[] = $time + $this->oneDay*$i;
}

//把加班和放假的数据单独提出来防止多次循环后出现内存泄漏
if(isset($this->festivalTime['time']))
{
$this->festivalTime['time'] = array_merge($this->festivalTime['time'], $data);
$this->festivalTime['repair'] = array_merge($this->festivalTime['repair'], $value['repair']);
}
else
{
$this->festivalTime['time'] = $data;
$this->festivalTime['repair'] = $value['repair'];
}
}
}

/**
* 生成工作日的原始数据
* @author zzw
* @DateTime 2019-10-09T14:24:47+0800
*/
private function generateData()
{
for ($i = 1; $i <= ($this->num-$this->key); $i++)
{
$this->WorkingDay[] = $this->time + $this->oneDay*$i;
}

$this->time = $this->WorkingDay[$this->num-1] + $this->oneDay;
}
}

add.html

<!DOCTYPE html>
<html>
<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节假日添加</title>

<script type="text/javascript" src="/static/jquery.min.js"></script>
<style>
.layui-form-select dl {
max-height: 200px;
}
</style>
</head>

<body>
<form action="">
<table>
<tr><td>所在年份:<input type="text" name="year" placeholder="请输入年份"></td></tr>
<tr>
<td>节日:<input type="text" name="name[]"></td>
<td>开始时间:<input type="text" name="addtime[]"></td>
<td>放假天数:<input type="text" name="num[]"></td>
<td>补班日期: <input type="text" name="repairTime[]"></td>
</tr>
<tr>
<td>节日:<input type="text" name="name[]"></td>
<td>开始时间:<input type="text" name="addtime[]"></td>
<td>放假天数:<input type="text" name="num[]"></td>
<td>补班日期: <input type="text" name="repairTime[]"></td>
</tr>
<tr>
<td>节日:<input type="text" name="name[]"></td>
<td>开始时间:<input type="text" name="addtime[]"></td>
<td>放假天数:<input type="text" name="num[]"></td>
<td>补班日期: <input type="text" name="repairTime[]"></td>
</tr>
<tr>
<td>节日:<input type="text" name="name[]"></td>
<td>开始时间:<input type="text" name="addtime[]"></td>
<td>放假天数:<input type="text" name="num[]"></td>
<td>补班日期: <input type="text" name="repairTime[]"></td>
</tr>
<tr>
<td>节日:<input type="text" name="name[]"></td>
<td>开始时间:<input type="text" name="addtime[]"></td>
<td>放假天数:<input type="text" name="num[]"></td>
<td>补班日期: <input type="text" name="repairTime[]"></td>
</tr>
<tr>
<td>节日:<input type="text" name="name[]"></td>
<td>开始时间:<input type="text" name="addtime[]"></td>
<td>放假天数:<input type="text" name="num[]"></td>
<td>补班日期: <input type="text" name="repairTime[]"></td>
</tr>
<tr>
<td>节日:<input type="text" name="name[]"></td>
<td>开始时间:<input type="text" name="addtime[]"></td>
<td>放假天数:<input type="text" name="num[]"></td>
<td>补班日期: <input type="text" name="repairTime[]"></td>
</tr>
</table>
<input id="addUser" type="button" value="立即保存">
</form>

<script type="text/javascript">
$('#addUser').on('click', function(){
$.ajax({
url:'{:url('Index/add')}',
type:"post",
dataType:"json",
data:$("form").serialize(),
timeout:30000,
success:function(result){
if(result[0]=='ERROR'){
alert('添加失败');
return false;
}
alert('添加成功')
window.location.href='{:url('Index/data')}?id='+result[1];
}
});
})

</script>
</body>
</html>

data.html

<!DOCTYPE html>
<html>
<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节假日管理</title>
<script type="text/javascript" src="/static/jquery.min.js"></script>
</head>

<body>
<form action="">
<input type="hidden" name="code" value="{$content['id']}">
<table>
<tr><td>所在年份:<input type="text" name="year" placeholder="请输入年份" value="{$content['year']}"></td></tr>
{volist name="list" id="vo"}
<tr>
<td>节日:<input type="text" name="name[]" value="{$vo.name}"></td>
<td>开始时间:<input type="text" name="addtime[]" value="{$vo.time}"></td>
<td>放假天数:<input type="text" name="num[]" value="{$vo.fatalism}"></td>
<td>补班日期: <input type="text" name="repairTime[]" value="{$vo.repair}"></td>
</tr>
{/volist}
</table>
<input id="addUser" type="button" value="立即保存">
</form>

<script type="text/javascript">
$('#addUser').on('click', function(){
$.ajax({
url:'{:url('Index/data')}',
type:"post",
dataType:"json",
data:$("form").serialize(),
timeout:30000,
success:function(result){
alert(result[1]);
if(result[0]=='ERROR'){
return false;
}

window.location.reload();
}
});
})

</script>
</body>
</html>

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节假日列表</title>
</head>
<style type="text/css">
table{border-top: 1px solid #ccc;border-left: 1px solid #ccc;}
table td{text-align: center;}
table td,table th{border-right: 1px solid #ccc;border-bottom: 1px solid #ccc;}
</style>
<body>
<a href="{:url('Index/add')}" target="_blank">添加</a>
<table width="100%">
<tr><th>id</th><th>年份</th><th>添加时间</th><th>操作</th></tr>
{volist name="list" id="vo"}
<tr><td>{$vo.id}</td><td>{$vo.year}</td><td>{$vo.addtime}</td><td><a href="{:url('Index/data')}?id={$vo['id']}">修改</a></td></tr>
{/volist}
</table>

</body>
</html>

festival.sql(只有一个表,所以就只把这个表的结构和测试数据放进去了)

/*
Navicat Premium Data Transfer

Source Server : 127.0.0.1
Source Server Type : MySQL
Source Server Version : 50553
Source Host : localhost:3306
Source Schema : zjcsinterface

Target Server Type : MySQL
Target Server Version : 50553
File Encoding : 65001

Date: 10/10/2019 11:08:35
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for how_festival
-- ----------------------------
DROP TABLE IF EXISTS `festival`;
CREATE TABLE `festival` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'id',
`year` smallint(4) NOT NULL COMMENT '年',
`festival` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`addtime` bigint(10) NOT NULL COMMENT '添加时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of how_festival
-- ----------------------------
INSERT INTO `festival` VALUES (1, 2019, '[{\"name\":\"\\u5143\\u65e6\",\"time\":\"2018-12-30\",\"fatalism\":\"3\",\"repair\":[\"2019-12-29\"]},{\"name\":\"\\u6625\\u8282\",\"time\":\"2019-02-04\",\"fatalism\":\"7\",\"repair\":[\"2019-02-02\",\"2019-02-03\"]},{\"name\":\"\\u6e05\\u660e\\u8282\",\"time\":\"2019-04-05\",\"fatalism\":\"3\",\"repair\":[]},{\"name\":\"\\u52b3\\u52a8\\u8282\",\"time\":\"2019-05-01\",\"fatalism\":\"4\",\"repair\":[\"2019-04-28\",\"2019-05-05\"]},{\"name\":\"\\u7aef\\u5348\\u8282\",\"time\":\"2019-06-07\",\"fatalism\":\"3\",\"repair\":[]},{\"name\":\"\\u4e2d\\u79cb\\u8282\",\"time\":\"2019-09-13\",\"fatalism\":\"3\",\"repair\":[]},{\"name\":\"\\u56fd\\u5e86\\u8282\",\"time\":\"2019-10-01\",\"fatalism\":\"7\",\"repair\":[\"2019-09-29\",\"2019-10-12\"]}]', 1558582312);

SET FOREIGN_KEY_CHECKS = 1;

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!