I am trying to set a start date and end date by the quarter.
For example, I am working on a reporting system where i need to report data for quarter 1, quarter 2, qu
This was my solution.
function getCurrentQuarter($timestamp=false){
if(!$timestamp)$timestamp=time();
$day = date('n', $timestamp);
$quarter = ceil($day/3);
return $quarter;
}
function getPreviousQuarter($timestamp=false){
if(!$timestamp)$timestamp=time();
$quarter = getCurrentQuarter($timestamp) - 1;
if($quarter < 0){
$quarter = 4;
}
return $quarter;
}
function getNextQuarter($timestamp=false){
if(!$timestamp)$timestamp=time();
$quarter = getCurrentQuarter($timestamp) + 1;
if($quarter > 4){
$quarter = 0;
}
return $quarter;
}
function getFirstAndLastDayOfQuarter($quarter, $year=false){
if(!$year)$year=date('Y');
$startDate = new DateTime($year.'-'.($quarter*3-2).'-1');
//Get first day of first month of next quarter
$endMonth = $quarter*3+1;
if($endMonth>12){
$endMonth = 1;
$year++;
}
$endDate = new DateTime($year.'-'.$endMonth.'-1');
//Subtract 1 second to get last day of prior month
$endDate->sub(new DateInterval('PT1S'));
return array($startDate, $endDate);
}
A versatile version would be:
$date = new DateTime(/* you may insert a date here, else its now */);
//$date->modify('-3 months'); // you may want last quarter or any other modifcation
$quarter = ceil($date->format('n')/3);
$start = new DateTime();
$start->setDate($date->format('Y'), (($quarter*3)-2), 1)->setTime(0, 0, 0, 0);
$end = new DateTime();
$end->setDate($date->format('Y'), ($quarter*3), 1);
$end->setDate($date->format('Y'), ($quarter*3), $end->format('t'))->setTime(0, 0, 0, 0);
echo $start->format('Y-m-d');
echo $end->format('Y-m-d');
this is simple yet effective. It let's you choose the input date and make relative adaptions with modify.
You can simply this greatly using basic math.
Each Month number minus 1 % 3 will tell how many months you are offset from the current quarter..
/**
* @param DateTime $date
* @return array
*/
function getQuarterRangeFromDate(DateTime $date)
{
// Clone the date to avoid modifying your date in current context
$quarter_start = clone($date);
// Find the offset of months
$months_offset = ($date->format('m') - 1) % 3;
// Modify quarter date
$quarter_start->modify(" - " . $months_offset . " month")
->modify("first day of this month");
$quarter_end = clone($quarter_start);
$quarter_end->modify("+ 3 month");
return [$quarter_start, $quarter_end];
}
Try to use DateTime function. For your example, is look like:
case 'this_month':
$start_date = new DateTime('first day of this month');
$end_date = new DateTime('last day of this month');
break;
case 'last_month':
$start_date = new DateTime('first day of next month');
$end_date = new DateTime('last day of next month');
break;
echo $start_date->format(DATE_FORMAT);
echo $end_date->format(DATE_FORMAT);
And if you want to get the first and last days of quarter, try to use:
$start_date = new DateTime('first day of January');
$end_date = new DateTime('last day of March');
echo $start_date->format(DATE_FORMAT);
echo $end_date->format(DATE_FORMAT);
Or use function strtotime. Example with strtotime:
$quarter_start = strtotime('first day of January');
$quarter_end = strtotime('last day of March');
echo date(DATE_FORMAT, $quarter_start);
echo date(DATE_FORMAT, $quarter_end);
Just wanted to point SynaTree's solution doesn't work for every last 3rd month in quarter.
Here's a modified solution using DateTime.
$now = new DateTimeImmutable();
$offset = ($now->format('n') - 1) % 3;
$start = $now->modify("first day of -{$offset} month midnight");
$endExcluded = $start->modify("+3 month");
$endIncluded = $start->modify("+3 month -1 second");
$endExcluded
works well when for DatePeriod loops, where the end date is excluded when time is 00:00:00.
/**
* Compute the start and end date of some fixed o relative quarter in a specific year.
* @param mixed $quarter Integer from 1 to 4 or relative string value:
* 'this', 'current', 'previous', 'first' or 'last'.
* 'this' is equivalent to 'current'. Any other value
* will be ignored and instead current quarter will be used.
* Default value 'current'. Particulary, 'previous' value
* only make sense with current year so if you use it with
* other year like: get_dates_of_quarter('previous', 1990)
* the year will be ignored and instead the current year
* will be used.
* @param int $year Year of the quarter. Any wrong value will be ignored and
* instead the current year will be used.
* Default value null (current year).
* @param string $format String to format returned dates
* @return array Array with two elements (keys): start and end date.
*/
public static function get_dates_of_quarter($quarter = 'current', $year = null, $format = null)
{
if ( !is_int($year) ) {
$year = (new DateTime)->format('Y');
}
$current_quarter = ceil((new DateTime)->format('n') / 3);
switch ( strtolower($quarter) ) {
case 'this':
case 'current':
$quarter = ceil((new DateTime)->format('n') / 3);
break;
case 'previous':
$year = (new DateTime)->format('Y');
if ($current_quarter == 1) {
$quarter = 4;
$year--;
} else {
$quarter = $current_quarter - 1;
}
break;
case 'first':
$quarter = 1;
break;
case 'last':
$quarter = 4;
break;
default:
$quarter = (!is_int($quarter) || $quarter < 1 || $quarter > 4) ? $current_quarter : $quarter;
break;
}
if ( $quarter === 'this' ) {
$quarter = ceil((new DateTime)->format('n') / 3);
}
$start = new DateTime($year.'-'.(3*$quarter-2).'-1 00:00:00');
$end = new DateTime($year.'-'.(3*$quarter).'-'.($quarter == 1 || $quarter == 4 ? 31 : 30) .' 23:59:59');
return array(
'start' => $format ? $start->format($format) : $start,
'end' => $format ? $end->format($format) : $end,
);
}
I develop this function to deal with quarter in any way: relative (this, previous, first, last) and fixed.
Examples:
get_dates_of_quarter();
//return current quarter start and end dates
get_dates_of_quarter(2);
//return 2nd quarter start and end dates of current year
get_dates_of_quarter('first', 2010, 'Y-m-d');
//return start='2010-01-01' and end='2014-03-31'
get_dates_of_quarter('current', 2009, 'Y-m-d');
//Supposing today is '2014-08-22' (3rd quarter), this will return
//3rd quarter but of year 2009.
//return start='2009-07-01' and end='2009-09-30'
get_dates_of_quarter('previous');
//Supposing today is '2014-02-18' (1st quarter), this will return
//return start='2013-10-01' and end='2013-12-31'
Waiting this help someone ;)