PHP天差计算错误
PHP days difference calculation error
我有一些 PHP 代码来计算两个特定日期之间的天数。差异不应计入星期日和星期六。另外,我有一个日期数组,其中包括假期,也需要跳过。
我将开始日期设为 01-05-2015
,将结束日期设为 01-06-2015
。我把 5 月份的所有日子都作为数组给出。因此,差异应为 1 天。但我得到的输出为 7。问题是什么?这是代码。
function dateRange($first, $last) {
$dates = array();
$current = strtotime($first);
$now = $current;
$last = strtotime($last);
while( $current <= $last ) {
if (date('w', $current) != 0){
$dates[] = date('d-m-Y', $current);
}
$current = strtotime('+1 day', $current);
}
unset($dates[0]);
return $dates;
}
$datea = "01-05-2015";
$date = "01-06-2015";
$hdsarray = array("1-05-2015","2-05-2015","4-05-2015","5-05-2015","7-05-2015","8-05-2015","9-05-2015","11-05-2015","12-05-2015","14-05-2015","15-05-2015","16-05-2015","18-05-2015","19-05-2015","21-05-2015","22-05-2015","23-05-2015","25-05-2015","26-05-2015","28-05-2015","29-05-2015","30-05-2015");
$datesarray = dateRange($datea, $date);
$result = array_diff($hdsarray,$datesarray);
$date_diff = sizeof($result);
echo $date_diff;
我能看到的唯一问题是 array_diff
的用法,它实际上包括被 dateRange
函数排除的星期六和星期日,如果在假期列表中找不到的话。
相反,您可以在 dateRange
函数中传递您的假期日期,并在那里进行过滤。
function dateRange($first, $last, $excludeDates) {
$dates = array();
$current = strtotime($first);
$now = $current;
$last = strtotime($last);
while( $current <= $last ) {
if (date('w', $current) != 0 && date('w', $current) != 6 && !in_array(date('j-m-Y', $current), $excludeDates)){
$dates[] = date('d-m-Y', $current);
}
$current = strtotime('+1 day', $current);
}
return $dates;
}
$datea = "01-05-2015";
$date = "01-06-2015";
$hdsarray = array("1-05-2015","2-05-2015","4-05-2015","5-05-2015","7-05-2015","8-05-2015","9-05-2015","11-05-2015","12-05-2015","14-05-2015","15-05-2015","16-05-2015","18-05-2015","19-05-2015","21-05-2015","22-05-2015","23-05-2015","25-05-2015","26-05-2015","28-05-2015","29-05-2015","30-05-2015");
$datesarray = dateRange($datea, $date, $hdsarray);print_r($datesarray);
结果:
Array
(
[0] => 06-05-2015
[1] => 13-05-2015
[2] => 20-05-2015
[3] => 27-05-2015
[4] => 01-06-2015
)
所有 5 个日期都出现在结果中,不包括周六、周日,也没有出现在假期列表中。
这里好像有几个问题。首先,正如其他人指出的那样,条件是:
if (date('w', $current) != 0){
只检查星期天,如果它还应该包括星期六,它应该是:
if (date('w', $current) != 0 && date('w', $current) != 6){
其次,$hdsarray
数组似乎没有包含五月的所有天数。似乎所有的星期三都不见了。
第三个问题是您在两个数组上使用 array_diff,一个包含日期,另一个包含字符串。来自文档:
Two elements are considered equal if and only if (string) $elem1 ===
(string) $elem2. In words: when the string representation is the same.
在您的 $hdsarray
中,您使用 "1-05-2015"
表示该月的第一天,而:
echo date('d-m-Y', strtotime("1-05-2015"));
结果 "01-05-2015"
。您需要在 $hdsarray
中为这些日期添加一个额外的 0
或使用日期。
最后但同样重要的是,如果 $hdsarray
包含星期六或星期日的日期,当前算法将无法正常工作,array_diff
的结果仍将包含这些日期。由于您想过滤 daterange
的结果,因此 array_filter 函数可能更合适。
尽管已经提供了答案,这里有一个 class 为您处理一切的小片段:
<?php
class dateRange {
protected $start, $end, $daysToExclude, $datesToExclude;
function __construct($dateStart, $dateEnd, $daysToExclude, $datesToExclude) {
$this->start = $dateStart;
$this->end = $dateEnd;
$this->daysToExclude = $daysToExclude;
$this->datesToExclude = $this->fixFormat($datesToExclude);
}
public function getRangeLength ($callback = null) {
$tmp = array();
$now = strtotime($this->start);
$to = strtotime($this->end);
while ( $now <= $to ) {
if (!in_array(date("w", $now), $this->daysToExclude)) {
$tmp[] = date('d-m-Y', $now);
}
$now = strtotime('+1 day', $now);
}
is_callable($callback) && call_user_func($callback, array_diff($tmp,$this->datesToExclude));
return count(array_diff($tmp,$this->datesToExclude));
}
private function fixFormat($el) {
if (!is_array($el)) {
return false;
}
else {
foreach ($el as &$value) {
$value = date("d-m-Y",strtotime($value));
}
return $el;
}
}
}
?>
我决定保留你目前的逻辑(使用 date_diff),但我认为,在未来,你的老板可能会告诉你 "You know what? I don't want to have mondays aswell there" 所以,在目前的系统下,你将不得不手动编辑您的功能,也许您将不再记得您所做的事情。
上面的class需要四个参数:
- 日期开始(d-m-Y 格式)
- dateEnd(d-m-Y 格式)
- daysToExclude(包含要排除的日期的 ID 的数组 -> 示例数组 (0,6) 以排除周六和周日)。
- datesToExclude(包含要排除的日期的数组,支持每种格式)。
class 将自动修复 datesToExclude 数组格式,以便您可以使用 date_diff。
根据您的情况,这是一个使用它的示例:
<?php
$dateStart = "01-05-2015";
$dateEnd = "01-06-2015";
$daysToExclude = array(0,6);
$exclusions = array(
"1-05-2015",
"2-05-2015",
"4-05-2015",
"5-05-2015",
"7-05-2015",
"8-05-2015",
"9-05-2015",
"11-05-2015",
"12-05-2015",
"14-05-2015",
"15-05-2015",
"16-05-2015",
"18-05-2015",
"19-05-2015",
"21-05-2015",
"22-05-2015",
"23-05-2015",
"25-05-2015",
"26-05-2015",
"28-05-2015",
"29-05-2015",
"30-05-2015"
);
$dateRange = new dateRange($dateStart, $dateEnd, $daysToExclude, $exclusions);
echo $dateRange->getRangeLength();
?>
上面的代码输出 5。
函数 getRangeLength 也接受回调并将 return date_diff 操作的 array
结果,因此您还可以:
$dateRange->getRangeLength(function($res) {
echo "Literal output: <br />";
print_r($res);
echo "<br />count is: " . count($res);
});
以上输出:
Literal output:
Array ( [3] => 06-05-2015 [8] => 13-05-2015 [13] => 20-05-2015 [18] => 27-05-2015 [21] => 01-06-2015 )
count is: 5
因此,如果您以后也需要删除星期一,您可以通过将 daysToExclude 更改为 array(0,1,6);
来轻松地做到这一点
尽管已经发布了有效的答案,但希望这对需要它的其他人有所帮助。
无论如何,您最初的问题与 array_diff
函数密切相关,该函数没有发挥作用,因为日期字符串不兼容,因为“1-01- 2015”与“01-01-2015”不同,除非您先将两者都转换为时间,然后再转换回日期。
代码很好(除了根本没有使用$now
)。问题是 $hdsarray
是错误的:
应该$hdsarray = array("01-05-2015", "02-05-2015", "04-05-2015", "05-05-2015", "07-05-2015", "08-05-2015", "09-05-2015",...);
date('d-m-Y', $current);
对于 1 到 9 之间的所有日子,总是 return 前导 0。
这就是差异的来源。
我有一些 PHP 代码来计算两个特定日期之间的天数。差异不应计入星期日和星期六。另外,我有一个日期数组,其中包括假期,也需要跳过。
我将开始日期设为 01-05-2015
,将结束日期设为 01-06-2015
。我把 5 月份的所有日子都作为数组给出。因此,差异应为 1 天。但我得到的输出为 7。问题是什么?这是代码。
function dateRange($first, $last) {
$dates = array();
$current = strtotime($first);
$now = $current;
$last = strtotime($last);
while( $current <= $last ) {
if (date('w', $current) != 0){
$dates[] = date('d-m-Y', $current);
}
$current = strtotime('+1 day', $current);
}
unset($dates[0]);
return $dates;
}
$datea = "01-05-2015";
$date = "01-06-2015";
$hdsarray = array("1-05-2015","2-05-2015","4-05-2015","5-05-2015","7-05-2015","8-05-2015","9-05-2015","11-05-2015","12-05-2015","14-05-2015","15-05-2015","16-05-2015","18-05-2015","19-05-2015","21-05-2015","22-05-2015","23-05-2015","25-05-2015","26-05-2015","28-05-2015","29-05-2015","30-05-2015");
$datesarray = dateRange($datea, $date);
$result = array_diff($hdsarray,$datesarray);
$date_diff = sizeof($result);
echo $date_diff;
我能看到的唯一问题是 array_diff
的用法,它实际上包括被 dateRange
函数排除的星期六和星期日,如果在假期列表中找不到的话。
相反,您可以在 dateRange
函数中传递您的假期日期,并在那里进行过滤。
function dateRange($first, $last, $excludeDates) {
$dates = array();
$current = strtotime($first);
$now = $current;
$last = strtotime($last);
while( $current <= $last ) {
if (date('w', $current) != 0 && date('w', $current) != 6 && !in_array(date('j-m-Y', $current), $excludeDates)){
$dates[] = date('d-m-Y', $current);
}
$current = strtotime('+1 day', $current);
}
return $dates;
}
$datea = "01-05-2015";
$date = "01-06-2015";
$hdsarray = array("1-05-2015","2-05-2015","4-05-2015","5-05-2015","7-05-2015","8-05-2015","9-05-2015","11-05-2015","12-05-2015","14-05-2015","15-05-2015","16-05-2015","18-05-2015","19-05-2015","21-05-2015","22-05-2015","23-05-2015","25-05-2015","26-05-2015","28-05-2015","29-05-2015","30-05-2015");
$datesarray = dateRange($datea, $date, $hdsarray);print_r($datesarray);
结果:
Array
(
[0] => 06-05-2015
[1] => 13-05-2015
[2] => 20-05-2015
[3] => 27-05-2015
[4] => 01-06-2015
)
所有 5 个日期都出现在结果中,不包括周六、周日,也没有出现在假期列表中。
这里好像有几个问题。首先,正如其他人指出的那样,条件是:
if (date('w', $current) != 0){
只检查星期天,如果它还应该包括星期六,它应该是:
if (date('w', $current) != 0 && date('w', $current) != 6){
其次,$hdsarray
数组似乎没有包含五月的所有天数。似乎所有的星期三都不见了。
第三个问题是您在两个数组上使用 array_diff,一个包含日期,另一个包含字符串。来自文档:
Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same.
在您的 $hdsarray
中,您使用 "1-05-2015"
表示该月的第一天,而:
echo date('d-m-Y', strtotime("1-05-2015"));
结果 "01-05-2015"
。您需要在 $hdsarray
中为这些日期添加一个额外的 0
或使用日期。
最后但同样重要的是,如果 $hdsarray
包含星期六或星期日的日期,当前算法将无法正常工作,array_diff
的结果仍将包含这些日期。由于您想过滤 daterange
的结果,因此 array_filter 函数可能更合适。
尽管已经提供了答案,这里有一个 class 为您处理一切的小片段:
<?php
class dateRange {
protected $start, $end, $daysToExclude, $datesToExclude;
function __construct($dateStart, $dateEnd, $daysToExclude, $datesToExclude) {
$this->start = $dateStart;
$this->end = $dateEnd;
$this->daysToExclude = $daysToExclude;
$this->datesToExclude = $this->fixFormat($datesToExclude);
}
public function getRangeLength ($callback = null) {
$tmp = array();
$now = strtotime($this->start);
$to = strtotime($this->end);
while ( $now <= $to ) {
if (!in_array(date("w", $now), $this->daysToExclude)) {
$tmp[] = date('d-m-Y', $now);
}
$now = strtotime('+1 day', $now);
}
is_callable($callback) && call_user_func($callback, array_diff($tmp,$this->datesToExclude));
return count(array_diff($tmp,$this->datesToExclude));
}
private function fixFormat($el) {
if (!is_array($el)) {
return false;
}
else {
foreach ($el as &$value) {
$value = date("d-m-Y",strtotime($value));
}
return $el;
}
}
}
?>
我决定保留你目前的逻辑(使用 date_diff),但我认为,在未来,你的老板可能会告诉你 "You know what? I don't want to have mondays aswell there" 所以,在目前的系统下,你将不得不手动编辑您的功能,也许您将不再记得您所做的事情。
上面的class需要四个参数:
- 日期开始(d-m-Y 格式)
- dateEnd(d-m-Y 格式)
- daysToExclude(包含要排除的日期的 ID 的数组 -> 示例数组 (0,6) 以排除周六和周日)。
- datesToExclude(包含要排除的日期的数组,支持每种格式)。
class 将自动修复 datesToExclude 数组格式,以便您可以使用 date_diff。
根据您的情况,这是一个使用它的示例:
<?php
$dateStart = "01-05-2015";
$dateEnd = "01-06-2015";
$daysToExclude = array(0,6);
$exclusions = array(
"1-05-2015",
"2-05-2015",
"4-05-2015",
"5-05-2015",
"7-05-2015",
"8-05-2015",
"9-05-2015",
"11-05-2015",
"12-05-2015",
"14-05-2015",
"15-05-2015",
"16-05-2015",
"18-05-2015",
"19-05-2015",
"21-05-2015",
"22-05-2015",
"23-05-2015",
"25-05-2015",
"26-05-2015",
"28-05-2015",
"29-05-2015",
"30-05-2015"
);
$dateRange = new dateRange($dateStart, $dateEnd, $daysToExclude, $exclusions);
echo $dateRange->getRangeLength();
?>
上面的代码输出 5。
函数 getRangeLength 也接受回调并将 return date_diff 操作的 array
结果,因此您还可以:
$dateRange->getRangeLength(function($res) {
echo "Literal output: <br />";
print_r($res);
echo "<br />count is: " . count($res);
});
以上输出:
Literal output:
Array ( [3] => 06-05-2015 [8] => 13-05-2015 [13] => 20-05-2015 [18] => 27-05-2015 [21] => 01-06-2015 )
count is: 5
因此,如果您以后也需要删除星期一,您可以通过将 daysToExclude 更改为 array(0,1,6);
尽管已经发布了有效的答案,但希望这对需要它的其他人有所帮助。
无论如何,您最初的问题与 array_diff
函数密切相关,该函数没有发挥作用,因为日期字符串不兼容,因为“1-01- 2015”与“01-01-2015”不同,除非您先将两者都转换为时间,然后再转换回日期。
代码很好(除了根本没有使用$now
)。问题是 $hdsarray
是错误的:
应该$hdsarray = array("01-05-2015", "02-05-2015", "04-05-2015", "05-05-2015", "07-05-2015", "08-05-2015", "09-05-2015",...);
date('d-m-Y', $current);
对于 1 到 9 之间的所有日子,总是 return 前导 0。
这就是差异的来源。