【问题标题】:Removing DateTime/Object from DatePeriod从 DatePeriod 中删除 DateTime/Object
【发布时间】:2018-07-13 23:02:39
【问题描述】:

我正在尝试创建一个过滤器,如果在列表中找不到日期(星期一、星期二等),我希望从我的 DatePeriod 中删除特定的 DateTime。这样我就可以说,我周一和周二工作。如果您发现这一天是星期四,请继续退出此循环并且不要包含它。

但是,我似乎无法执行此操作,因为当我遍历 DatePeriod 时,我无法取消设置任何内容,因为它不会将其视为数组。有没有办法做到这一点?代码如下:

//Get all the start and end dates of the holidays (This will be run iteratively)  
$get_st_date = $row['h_s_date'];
$get_end_date = $row['h_e_date'];
//Convert them to approprariate format to be used with DatePeriod   
$get_begin = new DateTime( "$get_st_date" );
$get_end = new DateTime( "$get_end_date");

//Add an extra day or else it will be omitted from the following process.
$get_end = $get_end->add(new DateInterval('P1D'));
//Count per day
$get_interval = DateInterval::createFromDateString('1 day');
$get_period = new DatePeriod($get_begin, $get_interval, $get_end);
//Iteration Count
$iter = 0;
foreach($get_period as $get_dt){
    //Find if date is  Saturday or Sunday. If it is, break that current loop.
    $iter++;
    $str_result = $get_dt->format('l');
    if($str_result == "Saturday") {continue;}
    elseif($str_result == "Sunday") {continue;}
    elseif(!preg_match("($str_result)", $e_d_w_p_w)){
        echo "<br>Don't count this day" . $str_result; 
        unset($get_period[$iter]); 
        continue;
    }

然后关闭结束标签(我没有在这里包含它,因为我做一些其他的事情。

从上面的代码中,我得到以下错误: “致命错误:未捕获的错误:不能使用 DatePeriod 类型的对象作为数组”

有解决办法吗?

澄清:$e_d_w_p_w 是“员工每周工作天数”
$e_d_w_p_w 的格式类似于“Monday;Tuesday;”等等

【问题讨论】:

  • $e_d_w_p_w 是否类似于字符串中以逗号分隔的日期列表?你能举个例子吗?
  • @ishegg 更新了问题,以提供关于 $e_d_w_p_w 的更好说明。 "$e_d_w_p_w 的格式类似于 "Monday;Tuesday" 等

标签: php date datetime time


【解决方案1】:

问题在于 DatePeriod 不是 数组,就像错误所说的那样。它只是具有所需的属性,以便制作所需的日期列表,但它不存储它们,因此您不能 unset() 列表中的特定日期。

您可以做的是创建一个新数组,而不是从DatePeriod 中删除不符合条件的日期,而只将符合条件的日期添加到这个新数组中:

<?php
$get_st_date = "2017-09-01";
$get_end_date = "2017-09-20";
//Convert them to approprariate format to be used with DatePeriod   
$get_begin = new DateTime( "$get_st_date" );
$get_end = new DateTime( "$get_end_date");

//Add an extra day or else it will be omitted from the following process.
$get_end = $get_end->add(new DateInterval('P1D'));
//Count per day
$get_interval = DateInterval::createFromDateString('1 day');
$get_period = new DatePeriod($get_begin, $get_interval, $get_end);

$e_d_w_p_w = "Monday;Tuesday;";
$workDays = [];
//Iteration Count
$iter = 0;
foreach($get_period as $get_dt) {
    //Find if date is  Saturday or Sunday. If it is, break that current loop.
    $iter++;
    $str_result = $get_dt->format('l');
    if($str_result == "Saturday") {continue;}
    elseif($str_result == "Sunday") {continue;}
    elseif(preg_match("($str_result)", $e_d_w_p_w)){
        $workDays[] = $get_dt;
    }
}
var_dump($workDays);

Demo

另外,我认为将$e_d_w_p_w 转换为数组并检查当前日期是否在该数组中可能会更简洁(更快;尽可能避免使用正则表达式):

$e_d_w_p_w = "Monday;Tuesday;";
$days = explode(";", $e_d_w_p_w); // transform to an array, separating by ;
array_pop($days); // remove the last element (assuming you always have a trailing ;

然后

elseif(in_array($str_result, $days)){
    $workDays[] = $get_dt;
}

【讨论】:

  • 这是一个非常棒的答案,绝对朝着正确的方向前进!事实证明,我的很多代码都必须重写才能在我的实际工作示例中适应这个解决方案。但是,您的答案适用于我提供的情况;我知道在哪里重写我的代码的唯一原因就是因为它。所以非常感谢!
  • 没问题!我很高兴你让它工作。祝你好运!
【解决方案2】:

我正在研究在 DatePeriod 内迭代特定日期的方法,Google 将我带到了这里。我最终为它编写了一个类 - 希望这对 OP 有所帮助。

DatePeriod_Filter gist

为了满足 OP 的需求,你可以这样使用它:

$e_d_w_p_w = "Monday;Tuesday;";

//Add an extra day or else it will be omitted from the following process.
$filter = new DatePeriod_Filter(
  new DateTime( '2017-09-01' ),
  new DateInterval( 'P1D' ),
  new DateTime( '2017-09-20 + 1 day' )
);

foreach( explode( ';', strtolower( trim( $e_d_w_p_w, ';' ) ) ) as $day )
  $filter->$day();

foreach( $filter as $date )
{
  // do something here
}

【讨论】:

    猜你喜欢
    • 2014-12-26
    • 2012-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 2021-09-06
    • 2020-02-24
    相关资源
    最近更新 更多