关于strtotime,使用-1 month可能出现的bug

先上例子:
[code lang=”php”]
<?php

//根据某日期,获取上个月,结果: 2018-03
echo date(‘Y-m’, strtotime(‘2018-03-31 -1 month’));
[/code]
早在二三年前,我就有做过一个需求:根据时间区间的筛选,获取工作排班的内容。

当时,我用php写了一个简单的日历排班。涉及到跨月动态计算“排班结果”时,我用strtotime去获取上个月和下个月。

一开始上线时,运行还挺好,结果到了下个月31号,再回去看历史结果,就发现数据错乱了。最后,纠其原因,发现是月份获取出错了。

当时,不太理解为什么会出现这种错乱,只是知道,如果跨月时,涉及到上个月或下个月,没有31号或30号时,就会出现这种问题。

最近,无意间看到一个php大神写的文章( http://www.laruence.com/2018/07/31/3207.html ),才明白问题所在。

如上页面的例子,当2018-03-31时,获取上个月,理论上的结果是2018-02-31,但实际结果是2018-03-03。

但2月一般只有28,闰年也才29。31比28多了3天,所以结果应该是往后推了3天。如此类推,2018-10-31获取上个月,结果也是2018-10-01

红包分配方法:二倍均值法 和 线段切割法

[code lang=”php”]
<?php
/**
* 二倍均值法
* @param int $money 红包金额
* @param int $people 领取人数
* @return array 结果
*/
function double_average($money = 10, $people = 5)
{
$remain_people = $people; //剩余人数
$red_packet = []; //所有红包金额
//循环分配
for ($i = 0; $i < $people – 1; $i++) {
$get = mt_rand(1, $money / $remain_people * 2); //单个红包金额

$money -= $get; //剩余金额
$remain_people–; //剩余人数

$red_packet[] = $get; //存入金额
}
//最后一个包
$red_packet[] = $money;
//返回结果
return $red_packet;
}

/**
* 线段切割法
* @param int $money 红包金额
* @param int $people 领取人数
* @return array 结果
*/
function line_cut($money = 10, $people = 5)
{
//获取切割处
$temp = [];
while (count($temp) < $people – 1) {
$number = mt_rand(1, $money – 1);
$temp[$number] = 1;
}

//补头补尾
$temp[0] = 1;
$temp[$money] = 1;
$temp = array_keys($temp);
sort($temp);

//循环分配
$red_packet = [];
for ($i = 0; $i < $people; $i++) {
$red_packet[] = $temp[$i + 1] – $temp[$i];
}
//返回结果
return $red_packet;
}

var_dump(double_average());
var_dump(line_cut());
[/code]

参考来源:https://mp.weixin.qq.com/s/AIE33sdT2QI6UL8cs1kJCQ