I need to loop through the days between two dates in intervals of 20 days, including the last date. For example, between the dates 2019/01/01 and 2019/01/27 should return the following ranges:
2019-01-01 => 2019-01-20
2019-01-21 => 2019-02-09
2019-02-10 => 2019-02-27
I have tried with this code:
$start = new DateTime('2019-01-01');
$end = new DateTime('2019-02-27');
$interval = new DateInterval('P20D');
$period = new DatePeriod($start, $interval, $end, DatePeriod::EXCLUDE_START_DATE);
$from = $start->format('Y-m-d');
foreach ($period as $day) {
$to = $day->format('Y-m-d');
echo $from . ' => ' . $to . '<br>';
$from = $day->modify('+1 day')->format('Y-m-d');
}
Output:
2019-01-01 => 2019-01-21
2019-01-22 => 2019-02-10
This code has two problems, does not include the last period (no longer containing 20 days) and is advanced one day. How can I solve these problems?
This is probably more simply done by just incrementing the $start value by the $interval until it is greater than the $end value. Note that the interval needs to be 19 days to make a 20-day (inclusive of start and end) period.
$start = new DateTime('2019-01-01');
$end = new DateTime('2019-02-27');
$interval = new DateInterval('P19D');
while ($start < $end) {
echo $start->format('Y-m-d') . ' => ';
$start->add($interval);
echo min($start, $end)->format('Y-m-d') . "\n";
$start->add(new DateInterval('P1D'));
}
Output:
2019-01-01 => 2019-01-20
2019-01-21 => 2019-02-09
2019-02-10 => 2019-02-27
Demo on 3v4l.org
Update
Here is a version of the code that also skips weekends:
$start = new DateTime('2019-01-01');
$end = new DateTime('2019-02-27');
$interval = new DateInterval('P1D');
$days = 19;
while ($start < $end) {
echo $start->format('Y-m-d') . ' => ';
for ($i = 0; $i < $days; ) {
$start->add($interval);
$day_of_week = $start->format('N');
if ($day_of_week == 6 || $day_of_week == 7) continue;
$i++;
}
echo min($start, $end)->format('Y-m-d') . "\n";
$start->add($interval);
}
Demo on 3v4l.org
Related
I know how to get the previous Quarter number how to turn that into date ranges especially when it goes into the previous year?
$Quarter = floor((date('n') - 1) / 3);
Here you go:
function getQuarter(\DateTime $DateTime) {
$y = $DateTime->format('Y');
$m = $DateTime->format('m');
switch($m) {
case $m >= 1 && $m <= 3:
$start = '01/01/'.$y;
$end = (new DateTime('03/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q1 '.$y;
break;
case $m >= 4 && $m <= 6:
$start = '04/01/'.$y;
$end = (new DateTime('06/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q2 '.$y;
break;
case $m >= 7 && $m <= 9:
$start = '07/01/'.$y;
$end = (new DateTime('09/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q3 '.$y;
break;
case $m >= 10 && $m <= 12:
$start = '10/01/'.$y;
$end = (new DateTime('12/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q4 '.$y;
break;
}
return array(
'start' => $start,
'end' => $end,
'title'=>$title,
'start_nix' => strtotime($start),
'end_nix' => strtotime($end)
);
}
print_r(getQuarter(new DateTime()));
Output
Array
(
[start] => 10/01/2018
[end] => 12/31/2018
[title] => Q4 2018
[start_nix] => 1538377200
[end_nix] => 1546243200
)
Sandbox
Your in luck I wrote this a wile ago ... This is sort of the brute force way of doing it, but hey it works. There is probably a "fancier" way, but whatever...
UPDATE
Based on some comments using DateTime has many advantages, besides just making the code in the function more concise. For example to get a previous quarter:
print_r(getQuarter((new DateTime())->modify('-3 Months'));
Output
Array
(
[start] => 07/01/2018
[end] => 09/30/2018
[title] => Q3 2018
[start_nix] => 1530428400
[end_nix] => 1538290800
)
Sandbox
Here the extra parentheses are important (around new DateTime)
(new DateTime())->modify('-3 Months');
This causes the constructor to return the instance of the object, which lets you immediately call modify on it. It's equivalent to doing this:
$DateTime = new DateTime();
$DateTime->modify('-3 Months');
But without creating a local variable.
And on the same token you can get the next quarter by doing
print_r(getQuarter((new DateTime())->modify('+3 Months'));
Another example of this is in the function itself (specifically):
(new DateTime('03/1/'.$y))->modify('Last day of this month')
What this does is get the last day of whatever month the DateTime object has, in this case it's 3. So we don't have to even think of how many days that month has, it just returns the correct number. These are Relative Date formats
http://php.net/manual/en/datetime.formats.relative.php
One last one that may be of use to you is this one first day of ? this year where the ? is the month name. For example:
print_r(getQuarter((new DateTime())->modify('first day of january this year')));
print_r(getQuarter((new DateTime())->modify('first day of april this year')));
print_r(getQuarter((new DateTime())->modify('first day of july this year')));
print_r(getQuarter((new DateTime())->modify('first day of october this year')));
Effectively this will give you each quarter this year.
Hope that helps.
A simple one-liner for each start and end date would be:
$start = (new DateTime('first day of -' . (((date('n') - 1) % 3) + 3) . ' month'))->format('Y-m-d'); # first day of previous quarter
$end = (new DateTime('last day of -' . (((date('n') - 1) % 3) + 1) . ' month'))->format('Y-m-d'); # last day of previous quarter
DateTime can work with relative values so you can describe which date you want.
I am using this code. It uses DateTime object and its methods.
The main method is getCurrentQuarterStartDate(), the other 2 methods use it.
You can obtain not only dates of previous quarter, but of any other quarter in the past and in the future.
<?php
echo "Current quarter start: \n";
$dt = getCurrentQuarterStartDate();
var_dump($dt->format('Y-m-d'));
echo "Current quarter end: \n";
$dt = getRelativeQuarterEndDate(0);
var_dump($dt->format('Y-m-d'));
echo "Next quarter start: \n";
$dt = getRelativeQuarterStartDate(1);
var_dump($dt->format('Y-m-d'));
echo "Next quarter end: \n";
$dt = getRelativeQuarterEndDate(1);
var_dump($dt->format('Y-m-d'));
echo "Prev quarter start: \n";
$dt = getRelativeQuarterStartDate(-1);
var_dump($dt->format('Y-m-d'));
echo "Prev quarter end: \n";
$dt = getRelativeQuarterEndDate(-1);
var_dump($dt->format('Y-m-d'));
function getCurrentQuarterStartDate()
{
$dt = new DateTime('now', new DateTimeZone('Europe/Prague'));
$currentMonth = (int)$dt->format('m');
$currentYear = (int)$dt->format('Y');
$currentQuartalNr = ceil($currentMonth / 3); // returns 0.333-4 and it is ceiled to 1-4
$currentQuartalStartMonth = $currentQuartalNr * 3 - 2; // returns 1,4,7 or 10
$dt->setDate($currentYear, $currentQuartalStartMonth, 1);
return $dt;
}
/**
* #param $offset 0 = current quarter, 1 = next, -1 = prev, -2, +5 ...
*/
function getRelativeQuarterStartDate($offset = 0)
{
$currentQStartDate = getCurrentQuarterStartDate();
if ($offset == 0) {
return $currentQStartDate;
}
if ($offset > 0) {
$currentQStartDate->add(new \DateInterval('P' . $offset*3 . 'M'));
return $currentQStartDate;
}
if ($offset < 0) {
$currentQStartDate->sub(new \DateInterval('P' . abs($offset)*3 . 'M'));
return $currentQStartDate;
}
}
/**
* #param $offset 0 = current quarter, 1 = next, -1 = prev, -2, +5 ...
*/
function getRelativeQuarterEndDate($offset = 0)
{
$dt = getCurrentQuarterStartDate();
if ($offset >= 0) {
$dt->add(new \DateInterval('P' . $offset*3 . 'M'));
}
if ($offset < 0) {
$dt->sub(new \DateInterval('P' . abs($offset)*3 . 'M'));
}
$dt->add(new \DateInterval('P3M'));
$dt->sub(new \DateInterval('P1D'));
return $dt;
}
Find Previous Quarter start and end date
function getpreviousQuarterData(\DateTime $DateTime) {
$y = $DateTime->format('Y');
$m = $DateTime->format('m');
switch($m) {
case $m >= 1 && $m <= 3:
$start = '10/01/'.$y-1;
$end = (new DateTime('12/1/'.$y-1))->modify('Last day of this month')->format('m/d/'.$y-1);
$title = 'Q4 '.$y-1;
break;
case $m >= 4 && $m <= 6:
$start = '01/01/'.$y;
$end = (new DateTime('03/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q1 '.$y;
break;
case $m >= 7 && $m <= 9:
$start = '04/01/'.$y;
$end = (new DateTime('06/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q2 '.$y;
break;
case $m >= 10 && $m <= 12:
$start = '07/01/'.$y;
$end = (new DateTime('09/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q3 '.$y;
break;
}
return array(
'start' => $start,
'end' => $end,
'title'=>$title,
'start_nix' => strtotime($start),
'end_nix' => strtotime($end)
);
}
I want to create time slots with start, end time & also break start and end.
I have achieved to generate the time slots but without the break between 11:10 - 11:25
LIVE CODE EXAMPLE
Input variables
$duration = 35; // how much the is the duration of a time slot
$cleanup = 0; // don't mind this
$start = '09:00'; // start time
$end = '12:00'; // end time
$break_start = '11:10'; // break start
$break_end = '11:25'; // break end
function availableSlots($duration, $cleanup, $start, $end) {
$start = new DateTime($start);
$end = new DateTime($end);
$interval = new DateInterval("PT" . $duration . "M");
$cleanupInterval = new DateInterval("PT" . $cleanup . "M");
$periods = array();
for ($intStart = $start; $intStart < $end; $intStart->add($interval)->add($cleanupInterval)) {
$endPeriod = clone $intStart;
$endPeriod->add($interval);
if ($endPeriod > $end) {
break;
}
$periods[] = $intStart->format('H:i A') . ' - ' . $endPeriod->format('H:i A');
}
return $periods;
}
Function will generate this output:
09:00 AM - 09:35 AM
09:35 AM - 10:10 AM
10:10 AM - 10:45 AM
10:45 AM - 11:20 AM
11:20 AM - 11:55 AM
What i need to achieve is 11:10am till 11:25am break period to be excluded from the results.
$break_start = '11:10';
$break_end = '11:25';
Try this...
I have modified your function
function availableSlots($duration, $cleanup, $start, $end, $break_start, $break_end) {
$start = new DateTime($start);
$end = new DateTime($end);
$break_start = new DateTime($break_start);
$break_end = new DateTime($break_end);
$interval = new DateInterval("PT" . $duration . "M");
$cleanupInterval = new DateInterval("PT" . $cleanup . "M");
$periods = array();
for ($intStart = $start; $intStart < $end; $intStart->add($interval)->add($cleanupInterval)) {
$endPeriod = clone $intStart;
$endPeriod->add($interval);
if(strtotime($break_start->format('H:i A')) < strtotime($endPeriod->format('H:i A')) && strtotime($endPeriod->format('H:i A')) < strtotime($break_end->format('H:i A'))){
$endPeriod = $break_start;
$periods[] = $intStart->format('H:i A') . ' - ' . $endPeriod->format('H:i A');
$intStart = $break_end;
$endPeriod = $break_end;
$intStart->sub($interval);
}else{
$periods[] = $intStart->format('H:i A') . ' - ' . $endPeriod->format('H:i A');
}
}
return $periods;
}
$duration = 35; // how much the is the duration of a time slot
$cleanup = 0; // don't mind this
$start = '09:00'; // start time
$end = '12:00'; // end time
$break_start = '11:10'; // break start
$break_end = '11:25'; // break end
availableSlots($duration, $cleanup, $start, $end, $break_start, $break_end);
The Result will be:
Array
(
[0] => 09:00 AM - 09:35 AM
[1] => 09:35 AM - 10:10 AM
[2] => 10:10 AM - 10:45 AM
[3] => 10:45 AM - 11:10 AM
[4] => 11:25 AM - 12:00 PM
)
I have a variable called $conn_date which value is 2016-09-18.
Now I want to show all months from 2016-09-18 to till now. But using bellow php code I can't get current month.
$begin = new DateTime($conn_date); // value is : 2016-09-18
$end = new DateTime( date("Y-m-d") );
$interval = DateInterval::createFromDateString('1 Month');
$period = new DatePeriod($begin, $interval, $end);
$ok = array();
foreach ( $period as $k=>$dt ) {
if ( $dt->format("Y-m-d") ) {
$ok[] = $dt->format("Y-m-d");
}
}
echo '<pre>';
print_r($ok);
echo '</pre>';
Output :
Array
(
[0] => 2016-09-18
[1] => 2016-10-18
[2] => 2016-11-18
[3] => 2016-12-18
)
I want to show current months too, How can I do this ?
$begin = new DateTime($conn_date); // value is : 2016-09-18
$end = new DateTime( date("Y-m-d") );
$end->add(new DateInterval("P1M"));
$interval = DateInterval::createFromDateString('1 Month');
$period = new DatePeriod($begin, $interval, $end);
$ok = array();
foreach ( $period as $k=>$dt ) {
if ( $dt->format("Y-m-d") ) {
$ok[] = $dt->format("Y-m-d");
}
}
echo '<pre>';
print_r($ok);
echo '</pre>';
//Here "P1M" is a one-month duration, Visit http://php.net/manual/en/datetime.add.php
You just need to add one interval to your end date. In your case $end->modify('1 month')
So the full code:
$begin = new DateTime('2016-09-18');
$end = new DateTime();
$unitQty = '1 month';
$interval = DateInterval::createFromDateString($unitQty);
$period = new DatePeriod($begin, $interval, $end->modify($unitQty));
$ok = array();
foreach ( $period as $k=>$dt ) {
if ( $dt->format("Y-m-d") ) {
$ok[] = $dt->format("Y-m-d");
}
}
$a = "2007-01-01";
$b = "2008-02-15";
$i = date("Ym", strtotime($a));
while($i <= date("Ym", strtotime($b))){
echo $i."\n";
if(substr($i, 4, 2) == "12")
$i = (date("Y", strtotime($i."01")) + 1)."01";
else
$i++;
}
Hi I've created a while loop for dates. I want to increase the month my 1 every time. However it isn't working and instead it increments like this :
2009/06/01
2009/07/01
2009/09/01
2009/12/01
2010/04/01
2010/09/01
which isn't correct. I dont understand why it won't increment by 1 month. Any help would be much appreciated
<?php
$startdate = "2009/06/01";
$enddate = "2009/12/31";
$start = strtotime($startdate);
$end = strtotime($enddate);
$f = 0;
$t = 6;
$d = 0;
$currentdate = $start;
while($f < $t )
{
$cur_date = date('Y/m/d', $currentdate);
$currentdate = strtotime($f . ' month', $currentdate);
echo $cur_date . "<br />";
//echo $f . "<br />";
$f = $f + 1;
}
?>
It won't work because you're not adding 1 month each time.... you're adding 1 month in the first iteration, 2 in the second, 3 in the third, etc. because you're increasing the value of $f every iteration.
$begin = new DateTime('2009-06-01');
$end = new DateTime('2009-12-31');
$end = $end->modify('+1 day');
$interval = DateInterval::createFromDateString('1 month');
$period = new DatePeriod($begin, $interval, $end);
foreach($period as $dt) {
var_dump($dt->format( "Y-m-d" ));
}
I have date ranges called from and to.I want to convert it to weeks.
Suppose from date is 1-10-2014 and to date is 31-10-2014
Then result is:
1st week : 01-10-2014 to 04-10-2014
2nd : 05-102014 to 11-10-2014
3rd : 12-10-2014 to 18-10-2014
4th : 19-10-2014 to 25-10-2014
5th : 26-10-2014 to 31-10-2014
In php.I try several code but that didn't given the absolute result only give 01 to 7 , 8 to 14 etc.
Pls help.
I already try answers from
Get the date of one week from today with PHP in stack overflow
date("Y-m-d",strtotime("+1 week"));
This snippet uses Sunday as the first day of the week:
$start = new DateTime('2014-10-01');
$end = new DateTime('2014-10-31 23:59');
$interval = new DateInterval('P1D');
$dateRange = new DatePeriod($start, $interval, $end);
$weekNumber = 1;
$weeks = array();
foreach ($dateRange as $date) {
$weeks[$weekNumber][] = $date->format('Y-m-d');
if ($date->format('w') == 6) {
$weekNumber++;
}
}
Each week will have all the days in it.
If you just want the first and last days of each week then you can just use array_shift and array_pop to get them. For example, for the first week you can use:
$wk1Start = array_shift($weeks[1]); //gives you first day of week 1
$wk1End = array_pop($weeks[1]); // give you the last day of week 1
If you want the start and end dates for each week, here is a way of doing it:
$ranges = array_map(function($week) {
return 'start: ' . array_shift($week)
. ', end: ' . array_pop($week); },
$weeks);
This is the output of $ranges for me:
Array
(
[1] => start: 2014-10-01, end: 2014-10-04
[2] => start: 2014-10-05, end: 2014-10-11
[3] => start: 2014-10-12, end: 2014-10-18
[4] => start: 2014-10-19, end: 2014-10-25
[5] => start: 2014-10-26, end: 2014-10-31
)
You can easily change the week starting day (set to Monday at the moment):
$fromDate = '2018-05-03';
$toDate = '2018-08-11';
$result = getWeekRanges($fromDate, $toDate);
array_walk_recursive($result, 'applyFormat');
echo '<pre>';
print_r($result);
echo '</pre>';
function getWeekRanges($start, $end) {
$timeStart = strtotime($start);
$timeEnd = strtotime($end);
$out = [];
$milestones[] = $timeStart;
$timeEndWeek = strtotime('next Monday', $timeStart);
while ($timeEndWeek < $timeEnd) {
$milestones[] = $timeEndWeek;
$timeEndWeek = strtotime('+1 week', $timeEndWeek);
}
$milestones[] = $timeEnd;
$count = count($milestones);
for ($i = 1; $i < $count; $i++) {
if( $i == $count - 1) {
$out[] = [
'start' => $milestones[$i - 1],
'end' => $milestones[$i]
];
}else{
$out[] = [
'start' => $milestones[$i - 1],
'end' => $milestones[$i] - 1
];
}
}
return $out;
}
function applyFormat(&$item) {
$item = date('Y-m-d', $item);
}
Try
$start_date = date('Y-m-d', strtotime('2014-10-01'));
$end_date = date('Y-m-d', strtotime('2014-10-31'));
$i=1;
for($date = $start_date; $date <= $end_date; $date = date('Y-m-d', strtotime($date. ' + 7 days'))) {
echo getWeekDates($date, $start_date, $end_date, $i);
echo "\n";
$i++;
}
function getWeekDates($date, $start_date, $end_date, $i) {
$week = date('W', strtotime($date));
$year = date('Y', strtotime($date));
$from = date("Y-m-d", strtotime("{$year}-W{$week}+1")); //Returns the date of monday in week
if($from < $start_date) $from = $start_date;
$to = date("Y-m-d", strtotime("{$year}-W{$week}-7")); //Returns the date of sunday in week
if($to > $end_date) $to = $end_date;
echo "$i th ".$from." to ".$to.'<br>';
}
output :-
1 th 2014-10-01 to 2014-10-05
2 th 2014-10-06 to 2014-10-12
3 th 2014-10-13 to 2014-10-19
4 th 2014-10-20 to 2014-10-26
5 th 2014-10-27 to 2014-10-31