cmprogram
cmprogram

Reputation: 1884

Removing DateTime/Object from DatePeriod

I'm trying to create a filter, whereby if days (Monday, Tuesday etc) are NOT found in a list, I want that specific DateTime to be removed from my DatePeriod. This is so that I can say, I work Monday and Tuesday. If you find that the day is Thursday, continue out of this loop and don't include it.

However, I cannot seem to do this as when I iterate through a DatePeriod, I cannot unset anything, as it does not count it as an array. Is there a way to do this? The code can be found below:

//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;
    }

Then close the end tags (I haven't included it here as I do some other stuff.

From the above code, I get the following error: "Fatal error: Uncaught Error: Cannot use object of type DatePeriod as array"

Is there a workaround to this?

For Clarification: $e_d_w_p_w is "Employee Days Worked Per Week"
$e_d_w_p_w is formatted like so "Monday;Tuesday;" etc

Upvotes: 2

Views: 981

Answers (2)

Jmweb
Jmweb

Reputation: 1

I was researching ways to iterate over certain days within a DatePeriod and Google led me here. I ended up writing a class for it - hopefully this helps the OP.

DatePeriod_Filter gist

To address the OP needs, you may use it like so:

$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
}

Upvotes: 0

ishegg
ishegg

Reputation: 9937

The problem is that DatePeriod is not an array, just like the error says. It just has the properties required so as to make the list of days required, but it doesn't store them, so you can't unset() a specific day from the list.

What you can do to accomplish this is create a new array, and instead of removing the days that do not match the criteria from the DatePeriod, only add the days that do to this new array:

<?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

Also, I think it might be a bit cleaner (and faster; avoid regular expressions whenever possible) to transform $e_d_w_p_w to an array and check if the current day is in that array:

$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 ;

and then

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

Upvotes: 1

Related Questions