PHP日期 - Unix时间戳

3

能有人帮我解决这个PHP时间戳谜题吗?

我想根据两个给定日期找出工作日的数量。

我得到一个字符串日期,例如开始日期:2019年10月1日,并将其拆分为数组 => $s

数组$s设置如下:

Array ( [0] => 01 [1] => 10 [2] => 2019 )

然后我从中生成了 Unix 时间戳:

date('U', mktime(0, 0, 0, $s[1], $s[0], $s[2]));

我得到了1569884400作为以上日期转换的结果。

然后我使用循环运行它,以便根据给定的两个日期找到工作日的数量。

这是循环的结果,可以看到由于某种原因10月27日重复出现。

只是为了澄清,这个PHP页面的顶部我设置了时区。

date_default_timezone_set('Europe/London');

以下是以下结果的代码

根据最后日期(在本例中为2019年10月31日,即31天),总计$total_days。

2019年10月应有23个工作日,由于我得到了两个27号,因此只有22个工作日。

我在这里做错了什么?

 $wk_days = array(1, 2, 3, 4, 5);
  $days = 0;
  for ($i = 0; $i < $total_days; $i++) {
    $tmp = $first + ($i * 86400);
    echo  $i." x86400 add to ". $first . " ==> " . $tmp. " and the new date is "  .date('Y-m-d',$tmp) ."<br/>";

    $chk = date('w', $tmp);

    if (in_array($chk, $wk_days)) {
      $days++;
    }
  }

0 x86400加上1569884400 ==> 1569884400 新日期是2019年10月1日

1 x86400加上1569884400 ==> 1569970800 新日期是2019年10月2日

2 x86400加上1569884400 ==> 1570057200 新日期是2019年10月3日

3 x86400加上1569884400 ==> 1570143600 新日期是2019年10月4日

4 x86400加上1569884400 ==> 1570230000 新日期是2019年10月5日

...

23 x86400加上1569884400 ==> 1571871600 新日期是2019年10月24日

24 x86400加上1569884400 ==> 1571958000 新日期是2019年10月25日

25 x86400加上1569884400 ==> 1572044400 新日期是2019年10月26日

26 x86400加上1569884400 ==> 1572130800 新日期是2019年10月27日 //***

27 x86400加上1569884400 ==> 1572217200 新日期是2019年10月27日 //***

28 x86400加上1569884400 ==> 1572303600 新日期是2019年10月28日

29 x86400加上1569884400 ==> 1572390000 新日期是2019年10月29日

30 x86400加上1569884400 ==> 1572476400 新日期是2019年10月30日


1
1569884400是9月30日,而不是10月1日。这可能是问题所在吗?(请注意,我还没有详细检查其余逻辑。)我认为首先应该仔细检查您在开头的转换。 - Andrew
1
你需要在午夜之前计算日期。为了避免在每年10月最后一个星期日从夏令时转换为冬令时时出现问题,你应该在中午12点计算日期。因此,请使用 date('U', mktime(12, 0, 0, $s[1], $s[0], $s[2])); - Pierre François
4个回答

2
你不需要那么复杂的东西。你可以使用简单的while循环来计算工作日。这可能不是最有效的方法,但应该可以工作。
function getNoOfWeekdays(string $startdate, string $enddate, string $format = 'd/m/Y'): int
{
    $start = date_create_from_format($format, $startdate);
    $end = date_create_from_format($format, $enddate);

    $count = 0;
    while ($start <= $end) {
        if ($start->format('N') < 6) $count++;
        $start->modify('+1 days');
    }

    return $count;
}

不必使用简单的while循环,也可以使用DatePeriod和DateInterval“+1 weekday”来完成。为此,必须修改开始日期。 - jspit

1

为了避免夏令时和冬令时的切换问题,请尝试使用这个方法(请参阅我上面的评论):

$first = date('U', mktime(12 /* 12 pm!! */, 0, 0, $s[1], $s[0], $s[2]));
//
// some code here that the author didn't show and we hardly can extrapolate
// ...
//
$wk_days = array(1, 2, 3, 4, 5);
  $days = 0;
  for ($i = 0; $i < $total_days; $i++) {
    $tmp = $first + ($i * 86400);
    echo  $i." x86400 add to ". $first . " ==> " . $tmp. " and the new date is "  .date('Y-m-d',$tmp) ."<br/>";

    $chk = date('w', $tmp);

    if (in_array($chk, $wk_days)) {
      $days++;
    }
  }

这是否意味着尽管我们引入了时区,但仍需手动处理夏令时? - user6640621
不,我的意思是,如果你从一天的边界(午夜)的时间戳计算日期,并且边界在一年中移动两次,在秋季有25小时的一天和春季有23小时的一天,那么你将会产生不必要的副作用。这就是为什么我建议你计算12点的当天时间戳,而不是午夜。 - Pierre François
过了一段时间,我意识到在伦敦时区可能行得通的事情,在南半球可能不行。更明智的做法是以一种不涉及时区和夏令时的方式进行日期计算。 - Pierre François
我按照你的建议更新了代码,现在它运行良好。感谢及时的帮助。 - user6640621

1
也许你可以尝试使用这段代码:
  $initial = "2019-10-01";
  $last = "2019-10-31";
  $wk_days = array(1, 2, 3, 4, 5);
  $days = 0;
  $date = $initial;
  do{

    $chk = date("w",strtotime($date));
    if(in_array($chk,$wk_days))
      $days++;
    $date = date("Y-m-d",strtotime("$date +1 day"));

  }while($date!=date("Y-m-d",strtotime("$last +1 day")));
    echo $days;
?>

1
我创建了一个名为dt的PHP扩展程序,用于DateTime API。您可以在这里找到它。使用它非常容易:
$start = '2019-10-01';
$end = '2019-11-01'; 

$start = dt::create($start);

//exclude end with true as 3.parameter
$countWeekdaysOct2019 = $start->countDaysTo('1,2,3,4,5',$end, true); //23

$countSundaysOct2019 = $start->countDaysTo('0',$end, true); //4

$countSaturdaysOct2019 = $start->countDaysTo('6',$end, true); //4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接