How to include the end date in a DatePeriod? - php

I am trying to get a Date range for all workdays this week. I have written the following code to do so.
Code
$begin = new DateTime('monday this week'); 2016-07-04
$end = clone $begin;
$end->modify('next friday'); // 2016-07-08
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval, $end);
foreach($daterange as $date) {
echo $date->format('Y-m-d')."<br />";
}
Output
2016-07-04
2016-07-05
2016-07-06
2016-07-07
In the output friday is missing. I can fix this by doing $end->modify('next saturday') but I was wondering why the last day of a DatePeriod is not included in the range.

The iterator seems to check the time as well as the date, it excludes the end element if the time in the endDate is less that or equal to the time in the start date.
So ensure the time of the end date is at least a second greater that that of the start date.
// this will default to a time of 00:00:00
$begin = new DateTime('monday this week'); //2016-07-04
$end = clone $begin;
// this will default to a time of 00:00:00
$end->modify('next friday'); // 2016-07-08
$end->setTime(0,0,1); // new line
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval, $end);
foreach($daterange as $date) {
echo $date->format('Y-m-d')."<br />";
}

Try this code
<?php
$begin = new DateTime('2016-07-04');
$end = clone $begin;
$end->modify('next friday'); // 2016-07-08
$end->modify('+1 day');
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval, $end);
foreach ($daterange as $date) {
echo $date->format('Y-m-d') . PHP_EOL;
}

In PHP 8.2 you can use DatePeriod::INCLUDE_END_DATE as constructor option!
https://www.php.net/manual/en/class.dateperiod.php#dateperiod.constants.include-end-date

Related

get time intervals with time range

I am trying to get time interval with custom start and end time variables for which i have searched and find its relevant information on this link.
I have tried the following code but its giving errorUncaught Error: Call to a member function date() on string
$start = date("H:i",strtotime('08:30 AM'));
$end = date("H:i",strtotime('06:00 PM'));
for($i = $start; $i <= $end; $i->modify(' +30 MINUTE')){
echo $i->date("H:i");
}
You need to use the builtin \DateTime class and the \DateInterval class as well
$begin = new DateTime('08:30:00');
$end = new DateTime('12:45:00');
$interval = DateInterval::createFromDateString('30 minute');
$period = new DatePeriod($begin, $interval, $end);
foreach ($period as $dt) {
echo $dt->format("H:i\n");
}
RESULTS
08:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
And if the time roles over to another day something like this
$begin = new DateTimeImmutable('2022-03-01 16:00:00');
$end = (new DateTime())->createFromImmutable($begin)->add(new DateInterval('P1D'))->settime(8,30,0);
$interval = DateInterval::createFromDateString('30 minute');
$period = new DatePeriod($begin, $interval, $end);
foreach ($period as $dt) {
echo $dt->format("d/m/Y H:i\n");
}

PHP confusion over reversing a DatePeriod iterator

I'm trying to work out how to invert my date period without pushing the data into an array and reversing it.
Say I would like a list of the last 5 Saturdays the following code will produce:
$begin = new DateTime( date('Y-m-d', strtotime("last Saturday")));
$begin->modify("- 4 weeks");
$end = new DateTime( date('Y-m-d', strtotime("last Saturday")));
$end = $end->modify( '+1 day' );
$interval = new DateInterval('P1W');
$periods = new DatePeriod($begin, $interval ,$end);
foreach($periods as $date){
echo $date->format("Y-m-d") . "\n";
}
2021-07-31
2021-08-07
2021-08-14
2021-08-21
2021-08-28
I would like this list reversed. So I figured I could make use of the DatePeriod invert property. Both the start and end of the DatePeriod look correct, with a result showing in the current element. However, interating over $period returns nothing:
$begin = new DateTime( date('Y-m-d', strtotime("last Saturday")));
$begin = $begin->modify( '+1 day' );
$end = new DateTime( date('Y-m-d', strtotime("last Saturday")));
$end->modify("- 4 weeks");
$interval = new DateInterval('P1W');
$interval->invert = 1;
$periods = new DatePeriod($begin, $interval ,$end);
foreach($periods as $date){
echo $date->format("Y-m-d") . "\n";
}
Update
So I've found a solution that calculates a diff of days and passes that to the end param in the DatePeriod constructor. It's not ideal but is working. Note the diff->days had to be divided by the days interval to prevent additional dates pulling through.
$start = new \DateTime( date('Y-m-d', strtotime("last Saturday")));
$end = new DateTime( date('Y-m-d', strtotime("last Saturday")));
$end->modify("- 4 weeks");
$diff = $end->diff($start);
$interval = new \DateInterval('PT0S'); //0 duration
$interval->d = -7; //negative value
$period = new \DatePeriod($start, $interval, $diff->days / 7);
foreach ($period as $date) {
echo $date->format('Y-m-d') . PHP_EOL;
}

Add datetime Value

I'm searching for the best way to echo day numbers in a week.
First i need to check what week there is.
And then echo all dates of the week into variables.
This is what i got:
//This Week Variable dates
$this_year = date('Y');
$this_week_no = date('W');
$this_week_mon = new DateTime();
$this_week_mon->setISODate($this_year,$this_week_no);
How do i rise tue by one day?
$this_week_tue = $this_week_mon ++;
You can use DateTime::modify():
$this_week_mon->modify('+1 day');
or DateTime::add() which accepts a DateInterval() object:
$this_week_mon->add(new DateInterval('P1D'));
You can loop through all of the days of the week using DatePeriod():
$start = new DateTime();
$start->setISODate($this_year,$this_week_no);
$end = clone $start;
$end->modify('+1 week');
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $date) {
echo $date->format('N');
}
$this_week_mon->modify('+1 day');
Should increment $this_week_mon by one day. To increase by more, just use days;
$this_week_mon->modify('+27 day');
Would increment by 27 days.

PHP get dates between two dates not working as expected

I am trying to get all dates between two dates using DatePeriod class. Its working fine when the dates inputed are of the same month, but not returning all dates when the two dates are of different months.
If the dates are say 2013-06-27 and 2013-07-05 its only returning 2013-06-27, 2013-06-28, 2013-06-29, 2013-06-30. Its not giving the rest of the dates.
CODE
$begin = new DateTime($start);
$last = new DateTime($end);
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $interval, $last);
I cannot reproduce the behavior
<?php
$start = '2013-06-27';
$end = '2013-07-05';
$begin = new DateTime($start);
$last = new DateTime($end);
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $interval, $last, DatePeriod::EXCLUDE_START_DATE);
echo 'phpversion: ', phpversion(), "\n";
foreach ( $period as $dt ) {
echo $dt->format("l Y-m-d H:i:s"), "\n";
}
echo "done.\n";
prints
phpversion: 5.4.7
Friday 2013-06-28 00:00:00
Saturday 2013-06-29 00:00:00
Sunday 2013-06-30 00:00:00
Monday 2013-07-01 00:00:00
Tuesday 2013-07-02 00:00:00
Wednesday 2013-07-03 00:00:00
Thursday 2013-07-04 00:00:00
done.
Which version of php do you use?

How to get a DatePeriod with "every first thursday in month"?

I'm having two DateTime-objects:
$start = new DateTime('first thursday of June 2012');
$end = new DateTime('2012-12-31');
I need a DatePeriod that contains all first Thursdays of the months between this two dates. When using
$interval = new DateInterval('P1M');
$period = new DatePeriod($start, $interval, $end);
This only adds 1 month without respecting the condition "first thursday".
Also something like this does not work:
$interval = DateInterval::createFromDateString('1 month first thursday');
$period = new DatePeriod($start, $interval, $end);
Does anyone know how I can achieve this?
I've struggled with this the last two hours - as soon as I posted it here I got the solution.
I only had to change the DateInterval string to "first thursday of next month".
$start = new DateTime('first thursday of June 2012');
$end = new DateTime('2012-12-31');
$interval = DateInterval::createFromDateString('first thursday of next month');
$period = new DatePeriod($start, $interval, $end);
Works! DateTime rocks ;-)

Categories