PHP. How to get a bimonthly recurring event? - php

I'm trying many approaches but then I get stuck half way.
Let's say order was created today. I need to display when the next recurring order will happen. So I have order created June 13, 2012. Then I have set the schedule to bimonthly recurring order, every 1st of month. How to calculate when the next recurring order will happen? The answer is August 1st.
If someone can outline an approach it would be very useful, it doesn't have to be code. This is what I have so far...
// first, get starting date
$start_date_month = date('m', strtotime($start_date));
// get this year
$this_year = date('Y');
// if this month is december, next month is january
$this_month = date('m', $timestamp_month);
if($this_month == 12){
$next_month = 1;
// if this month is not december add 1 to get next month
}else{
$next_month = $this_month + 1;
}
// get array of months where recurring orders will happen
$months = array();
for ($i=1; $i<=6; $i++) {
$add_month = $start_date_month+(2*$i); // 2, 4, 6, 8, 10, 12
if($add_month == 13){$add_month = 1;$year = $this_year+1;}
elseif($add_month == 14){$add_month = 2;$year = $this_year+1;}
elseif($add_month == 15){$add_month = 3;$year = $this_year+1;}
elseif($add_month == 16){$add_month = 4;$year = $this_year+1;}
elseif($add_month == 17){$add_month = 5;$year = $this_year+1;}
elseif($add_month == 18){$add_month = 6;$year = $this_year+1;}
elseif($add_month == 19){$add_month = 7;$year = $this_year+1;}
elseif($add_month == 20){$add_month = 8;$year = $this_year+1;}
else{$year = $this_year;}
echo $what_day.'-'.$add_month.'-'.$year.'<br />';
$months[] = $add_month;
}
echo '<pre>';
print_r($months);
echo '</pre>';
I don't want to simply find what's the date in two months from now. Let's say order created June 1. Next recurring order is August 1. Then let's say now, today is September 1st, but next recurring order is October 1st. See my dilemma?

Just take the current month, so since it's June, we get 6. 6 mod 2 == 0. Next month is July, we get 7. 7 mod 2 == 1.
So just check if current month % 2 == (first month % 2).
Then just check if it's the 1st of the month.
In PHP modulus is defined with the percentage symbol.
$month = date('n');
$createdMonth = 6;
if($month % 2 == $createdMonth % 2){
// stuff
}

You might find the library called When useful for this (I'm the author).
Here is code which will get you the next 2 recurring monthly dates (from todays date):
include 'When.php';
$r = new When();
$r->recur(new DateTime(), 'monthly')
->count(2)
->interval(2) // every other month
->bymonthday(array(1));
while($result = $r->next())
{
echo $result->format('c') . '<br />';
}
// output
// 2012-08-01T13:33:33-04:00
// 2012-10-01T13:33:33-04:00
Taking this a step further, you likely only want to find the 2 first business days:
include 'When.php';
$r = new When();
$r->recur(new DateTime(), 'monthly')
->count(2)
->interval(2) // every other month
->byday(array('MO', 'TU', 'WE', 'TH', 'FR')) // week days only
->bymonthday(array(1, 2, 3)) // the first weekday will fall on one of these days
->bysetpos(array(1)); // only return one per month
while($result = $r->next())
{
echo $result->format('c') . '<br />';
}
// output
// 2012-08-01T13:33:33-04:00
// 2012-10-01T13:33:33-04:00
Also note, the code is currently under a rewrite -- it works well but it is a little confusing and not well documented.

strtotime to the rescue:
<?php
date_default_timezone_set('Europe/London');
$d = new DateTime('2012-01-31');
$d->modify('first day of +2 months');
echo $d->format('r'), "\n";
?>

Let's say you want the next six orders:
$order_date = '6/13/2012';
$start = date('Y-m-01', strtotime($order_date));
$order_count = 6;
$future_orders = array();
$next = strtotime('+2 months', strtotime($start));
while(count($future_orders) < $order_count){
$future_orders[] = date('m/d/Y',$next);
$next = strtotime('+2 months', $next);
}
This can, obviously, be improved upon, but it should get you started ...

I got this:
$today = new DateTime();
$target_date = $today->modify("first day of +2 months");
echo "Your event is on " . $target_date->format("d/m/Y") . "!";

Related

Calculate the weeks between 2 dates manually in PHP

I'm trying to calculate the number of months and weeks since a particular date instead of from the beginning of the year.
It shouldn't follow calendar months but should instead count a month as every 4 weeks, and begin from a specified date. I need to be able to display the number of months, and also what week it is (1, 2, 3 or 4).
I want to put in a start date, and have it then count what month and week is it from that start date e.g if the start date is set to Mon 1st August it should show Month 1, Week 1 and so on.
My code is below. I tested it with some different start dates. Here's a list of what the code below generates and what it should display
Jun-20: Should be Week 2 - Shows as Week 0
Jun-27: Should be Week 1 - Shows as Week 3
Jul-04: Should be Week 4 - Shows as Week 2
Jul-11: Should be Week 3 - Shows as Week 1
Jul-18: Should be Week 2 - Shows as Week 0
$monthNumber = 5;
$monthStartDate = '2016-06-13';
$currentStartWeekDate = date('l') != 'Monday' ? date("Y-m-d", strtotime("last monday")) : date("Y-m-d"); // get the current week's Monday's date
$weekDateCounter = $monthStartDate;
$currentWeekNumber = 0;
while ($weekDateCounter != $currentStartWeekDate){
$currentWeekNumber += 1;
$weekDateCounter = date("Y-m-d", strtotime($weekDateCounter . "+7 days"));
//
if ($currentWeekNumber == 4){
$currentWeekNumber = 0; // reset week number
$monthNumber += 1; // increment month number
}
}
I am really at a loss with this and could use any help!
Your approach seems overly complicated:
function weekCounter($startDate,$endDate=null){
//use today as endDate if no date was supplied
$endDate = $endDate? : date('Y-m-d');
//calculate # of full weeks between dates
$secsPerWeek = 60 * 60 * 24 * 7;
$fullWeeks =
floor((strtotime($endDate) - strtotime($startDate))/$secsPerWeek);
$fullMonths = floor($fullWeeks/4);
$weeksRemainder = $fullWeeks % 4; // weeks that don't fit in a month
//increment from 0-base to 1-base, so first week is Week 1. Same with months
$fullMonths++; $weeksRemainder++;
//return months and weeks in an array
return [$fullMonths,$weeksRemainder];
}
You can call the function this way, and capture months and weeks:
//list() will assign the array members from weekCounter to the vars in list
list($months,$weeks) = weekCounter('2016-06-07'); //no end date, so today is used
//now $months and $weeks can be used as you wish
echo "Month: $months, Week: $weeks"; //outputs Month: 2, Week: 2
Live demo
The DateTime classes could make this much simpler for you. Documentation for them is here: http://php.net/manual/en/book.datetime.php
Try this out:
$date1 = new DateTime('2016-04-01');
$date2 = new DateTime('2016-07-24');
$diff = $date1->diff($date2);
$daysInbetween = $diff->days;
$weeksInbetween = floor($diff->days / 7);
$monthsInbetween = floor($weeksInbetween / 4);
print "Days inbetween = $daysInbetween" . PHP_EOL;
print "Weeks inbetween = $weeksInbetween" . PHP_EOL;
print "Months inbetween = $monthsInbetween" . PHP_EOL;
print "Total difference = $monthsInbetween months and "
. ($weeksInbetween - ($monthsInbetween * 4)) . " weeks" . PHP_EOL;
<?php
/**
* AUTHOR : VEDAVITH RAVULA
* DATE : 13122019
*/
function get_weeks($startDate = NULL,$endDate = NULL)
{
if(is_null($startDate) && is_null($endDate))
{
$startDate = date('Y-m-01');
$endDate = date('Y-m-t');
}
$date1 = new DateTime($startDate);
$date2 = new DateTime($endDate);
$interval = $date1->diff($date2);
$weeks = floor(($interval->days) / 7);
if(($date1->format("N") > 1) && ($date1->format("D") != "Sun"))
{
$diffrence = "-".( $date1->format("N"))." Days";
$date1 = $date1->modify($diffrence);
}
for($i = 0; $i <= $weeks; $i++)
{
if($i == 0)
{
$start_date = $date1->format('Y-m-d');
$date1->add(new DateInterval('P6D'));
}
else
{
$date1->add(new DateInterval('P6D'));
}
echo $start_date." - ".$date1->format('Y-m-d')."\n";
$date1->add(new DateInterval('P1D'));
$start_date = $date1->format('Y-m-d');
}
}
//function call
get_weeks("2021-11-01", "2021-11-14");

Php: How can I get the same date of the following months, quarterly and semi-annually

I'm this situation where users can choose to be billed either every month, quarter or semi-annual on one specific date the choose in a billing cycle. I'm using Laravel PHP framework.
Eg. Monthly - 5 May 2016, 5 June 2016, 5 July 2016, etc.
Billed on 5 on every month
Eg. Quarterly - 10 Jan 2016, 10 March 2016, 10 June 2016 etc...
Billed on 10 after every three months
Eg. Semi-Annually - 13 Apr 2016, 13 Sept 016
Billed on 13 after every six months.
The goal here is to get the same date on the every month the user choose to be billed, but in a month, quarterly or semi-annually.
This is my code after I play with #Rishi methode for some time
public function as_you_go($pay_as_you_go,$grand_total,$payment_date,$policy_id)
{
$policy = $this->findorFail($policy_id);
if($pay_as_you_go == 'Semi-Annually'){
$payments_no = 2;
$installment_amount = $grand_total/$payments_no;
$month_gap = 6;
$add_month = '+6 month';
}elseif($pay_as_you_go == 'Quarterly'){
$payments_no = 4;
$installment_amount = $grand_total/$payments_no;
$month_gap = 3;
$add_month = '+3 month';
}elseif($pay_as_you_go == 'Monthly'){
$payments_no = 12;
$installment_amount = $grand_total/$payments_no;
$month_gap = 1;
$add_month = '+1 month';
}
// Pay as you go calculations
for ($x = 0; $x < $payments_no; $x++) {
//$add_month = '+'.$x.' month';
$installment = new \App\Installment;
$installment->amount = $installment_amount;
if(\App\Installment::wherePayableType('App\Policy')->wherePayableId($policy->id)->first()){
$payment = \App\Installment::wherePayableType('App\Policy')->wherePayableId($policy->id)->orderBy('id', 'desc')->first();
$date = $payment->payment_date->format('Y-m-d');
$installment->payment_date = date('Y-m-d',strtotime($date.$add_month));
}else{
$installment->payment_date = $payment_date;
}
$installment->is_payed = 'No';
$policy->installments()->save($installment);
}
}
This is my function I wanted to generates dates according to user's date of choice based on semi-annual, quarterly and monthly payment gap.
Try like this
<?php
$date = '1-may-2016';
echo date('d-F-Y',strtotime($date.'+1 month'))."\n";
echo date('d-F-Y',strtotime($date.'+3 month'))."\n";
echo date('d-F-Y',strtotime($date.'+6 month'))."\n";
?>
check output here : https://eval.in/582424
Also you need to think about dates like $date = '30-jan-2016';.
I'm not entirely sure what you are looking for, but I think the following will help you on your way.
You can use DateTime and DateInterval to manipulate dates to add on a number of months.
// We have a DateTime object which is on the 5th may
$date = new DateTime('2016-05-05');
$billingType = 'monthly';
switch ($billingType) {
case 'monthly':
$interval = new DateInterval('P1M');
break;
case 'quarterly':
$interval = new DateInterval('P3M');
break;
case 'biannually':
$interval = new DateInterval('P6M');
break;
}
$newDate = clone $date;
$newDate->add($interval);
echo $date->format('Y-m-d'); // 2016-05-05
echo $newDate->format('Y-m-d'); // 2016-06-05
Let's say that you wanted to check if today is the day to bill someone...
function isBillingDate(DateTime $date, DateTime $billingDate, $billingType)
{
switch ($billingType) {
case 'monthly':
$interval = new DateInterval('P1M');
break;
case 'quarterly':
$interval = new DateInterval('P3M');
break;
case 'biannually':
$interval = new DateInterval('P6M');
break;
}
$isBillingDate = false;
$date->setTime(00, 00, 00);
$billingDate->setTime(00, 00, 00);
do {
if ($date == $billingDate) {
$isBillingDate = true;
} else {
$billingDate->add($interval);
}
} while ($isBillingDate === false && $date <= $billingDate);
return $isBillingDate;
}
$date = new DateTime('now'); // We want to check if we should bill them today (3rd June)
$billingStartDate = new DateTime('2016-05-03'); // They signed up to get billed on the 3rd of May
$billingType = 'monthly'; // They want to get billed every month
var_dump(isBillingDate($date, $billingStartDate, $billingType)); // True
$billingStartDate = new DateTime('2016-03-03'); // They signed up to get billed on the 3rd of March
$billingType = 'quarterly'; // They want to get billed quarterly
var_dump(isBillingDate($date, $billingStartDate, $billingType)); // True
$billingStartDate = new DateTime('2016-04-03'); // They signed up to get billed on the 3rd of April
$billingType = 'quarterly'; // They want to get billed quarterly
var_dump(isBillingDate($date, $billingStartDate, $billingType)); // False
Based on the code from Rishi I made this.
It splits the date to two parts and uses one to the month calculation and the other to the day.
Edit: noticed a quite obvious error in the code.
<?php
$date = '2016-01-26';
$date2= substr($date,0,7)."-01";
$period = "+3 month";
If(substr($date,-2) > date('t',strtotime($date2.$period))){
echo date('t-F-Y',strtotime($date2.$period))."\n";
}else{
echo date("d-", strtotime($date)) . date('F-Y',strtotime($date2.$period))."\n";
}
?>
https://eval.in/582564
Output:
From 31 of january:
28-February-2016
30-April-2016
31-July-2016
function iterateMonths(DateTime $date, $months = 1, $iterations = 12)
{
$day = $date->format('d');
for ($a = 0; $a < $iterations; $a++)
{
// Increment at least one month, but cap at the last day
$date->modify("last day of next month");
// Add on additional months if required
if ($months > 1)
{
$mDiff = $months-1;
$date->modify("+{$mDiff} months");
}
// If we are billing earlier than the last day of the month,
// rewind that number of days
if ($day < $date->format('d'))
{
$dDiff = $date->format('d') - $day;
$date->modify("-{$dDiff} days");
}
echo $date->format('Y-m-d'), PHP_EOL;
}
}
Standard monthly billing
$date = new \DateTime('2016-06-03');
iterateMonths($date);
// 2016-07-03, 2016-08-03, 2016-09-03, etc
Late days in months
$date = new \DateTime('2016-01-31');
iterateMonths($date, 1, 11);
// 2016-02-29, 2016-03-31, 2016-04-30, 2016-05-31
Quarterly (for four quarters)
$date = new \DateTime('2016-07-14');
iterateMonths($date, 3, 4);
// 2016-10-14, 2017-01-14, 2017-04-14, 2017-07-14

Loop the days of the month throughout the whole month

I am building multi-calendar, I have a horizontal looking interface:
I am trying to run the days of the week S,M,T,W,T,F,S
throughout the whole month instead of just the first 7 as in the picture.
the function which draw the calendar:
//our case "SUN"
if(AC_START_DAY=="sun"){
for($k=0; $k<7; $k++){
$weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li class="cal_weekday"> '.$weekday.'</li>';
}
}
//If we chose Monday as start week.
else{
if ($first_week_day == 0) $first_week_day =7;
for($k=1; $k<=7; $k++){
if($k==7) $weekday = mb_substr($lang["day_0"][0],0,1,'UTF-8');
else $weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li title="'.$lang["day_".$k.""].'"> '.$weekday.'</li>';
}
}
The lang file:
$lang["day_0"] = "Sunday";
$lang["day_1"] = "Monday";
$lang["day_2"] = "Tuesday";
$lang["day_3"] = "Wednesday";
$lang["day_4"] = "Thursday";
$lang["day_5"] = "Friday";
$lang["day_6"] = "Saturday";
Already defined
$month=sprintf("%02s",$month);
// define vars
$today_timestamp = mktime(0,0,0,date('m'),date('d'),date('Y')); # current timestamp - used to check if date is in past
$this_month = getDate(mktime(0, 0, 0, $month, 1, $year)); # convert month to timestamp
$first_week_day = $this_month["wday"]; # define first weekday (0-6)
$days_in_this_month = cal_days_in_month(CAL_GREGORIAN,$month,$year); # define number of days in week
$day_counter_tot = 0; # count total number of days showin INCLUDING previous and next months - use to get 6th row of dates
Looks like the $lang["day_".$k.""] is just counting the days from 0 to 6.. how can i make is loop untill the end of the month?
NOTE: I tried increasing the $k<7 just more empty blue boxes appear.
Use the loop to the 30/31 day.
And then change this line
$weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
to
$weekday = mb_substr($lang["day_".$k%7.""],0,1,'UTF-8');
This should give you the day 0 for every sunday.
0 % 7 = 0 (sunday)
1 % 7 = 1 (monday)
...
7 % 7 = 0 (sunday again)
8 % 7 = 1 (monday again)
You can use this code to generate all the days of the current month.
for ($date = strtotime(date('Y-m-01')); $date < strtotime(date('Y-m-t')); $date = strtotime("+1 day", $date)) {
echo date("l-d", $date)."<br>";
}
Will print all the days of the current month as follows.
Thursday-01
Friday-02
Saturday-03
Sunday-04
Monday-05
Tuesday-06
Wednesday-07
Thursday-08
Friday-09
Saturday-10
Sunday-11
Monday-12
Tuesday-13
Wednesday-14
Thursday-15
Friday-16
Saturday-17
Sunday-18
Monday-19
Tuesday-20
Wednesday-21
Thursday-22
Friday-23
Saturday-24
Sunday-25
Monday-26
Tuesday-27
Wednesday-28
Thursday-29
Friday-30
Looks like you almost got it right.
You only need to slightly modify your code to make it work the way you want it to.
You should just change your code to:
$number_of_days_in_the_future = 42; // Here you can put in the number of days for which you want to display the corresponding letter, and based on your screenshot that is 42
//our case "SUN"
if(AC_START_DAY=="sun"){
for($i=0; $i<$number_of_days_in_the_future; $i++){
$k = $i % 7;
$weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li class="cal_weekday"> '.$weekday.'</li>';
}
}
//If we chose Monday as start week.
else{
if ($first_week_day == 0) $first_week_day =7;
for($i=1; $i<=$number_of_days_in_the_future; $i++){
$k = $i % 7;
if($k==7) $weekday = mb_substr($lang["day_0"][0],0,1,'UTF-8');
else $weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li title="'.$lang["day_".$k.""].'"> '.$weekday.'</li>';
}
}
Please note that I only tried to fix your code so it works as you expect it to.
There's probably a more elegant solution but I don't really know your full code so I would just be guessing if I tried to offer you another approach.
I hope this will help you.
Cheers

Finding all weekdays in a month

How do I go about getting all the work days (mon-fri) in a given time period (let's say, today till the end of the next month) ?
If you're using PHP 5.2+ you can use the library I wrote in order to handle date recursion in PHP called When.
With the library, the code would be something like:
$r = new When();
$r->recur(<start date here>, 'weekly')
->until(<end date here>)
->wkst('SU')
->byday(array('MO', 'TU', 'WE', 'TH', 'FR'));
while($result = $r->next())
{
echo $result->format('c') . '<br />';
}
This sample does exactly what you need, in an quick and efficient way.
It doesn't do nested loops and uses the totally awesome DateTime object.
$oDateTime = new DateTime();
$oDayIncrease = new DateInterval("P1D");
$aWeekDays = array();
$sStart = $oDateTime->format("m-Y");
while($oDateTime->format("m-Y") == $sStart) {
$iDayInWeek = $oDateTime->format("w");
if ($iDayInWeek > 0 && $iDayInWeek < 6) {
$aWeekDays[] = clone $oDateTime;
}
$oDateTime->add($oDayIncrease);
}
Try it here: http://codepad.org/wuAyAqnF
To use it, simply pass a timestamp to get_weekdays. You'll get back an array of all the weekdays, as timestamps, for the rest of the current month. Optionally, you can pass a $to argument - you will get all weekdays between $from and $to.
function get_weekdays ($from, $to=false) {
if ($to == false)
$to = last_day_of_month($from);
$days = array();
for ($x = $from; $x < $to; $x+=86400 ) {
if (date('w', $x) > 0 && date('w', $x) < 6)
$days[] = $x;
}
return $days;
}
function last_day_of_month($ts=false) {
$m = date('m', $ts);
$y = date('y', $ts);
return mktime(23, 59, 59, ($m+1), 0, $y);
}
I suppose you could loop through the dates and check the day for each one, and increment a counter.
Can't think of anything else off the top of my head.
Pseudocode coming your way:
Calculate the number of days between now and the last day of the month
Get the current day of the week (i.e. Wednesday)
Based on the current day of the week, and the number of days left in the month, it's simple calculation to figure out how many weekend days are left in the month - it's going to be the number of days remaining in the month, minus the number of Sundays/Saturdays left in the month.
I would write a function, something like:
daysLeftInMonth(daysLeftInMonth, startingDayOfWeek, dayOfWeekToCalculate)
where:
daysLeftInMonth is last day of the month (30), minus the current date (15)
startingDayOfWeek is the day of the week you want to start on (for today it would be Wednesday)
dayOfWeekToCalculate is the day of the week you want to count, e.g. Saturday or Sunday. June 2011 currently has 2 Sunday, and 2 Saturdays left 'til the end of the month
So, your algorithm becomes something like:
getWeekdaysLeft(todaysDate)
...getWeekdaysLeft is something like:
sundaysLeft = daysLeftInMonth(lastDayOfMonth - todaysDate, "Wednesday", "Sunday");
saturdaysLeft = daysLeftInMonth(lastDayOfMonth - todaysDate, "Wednesday", "Saturday");
return ((lastDayOfMonth - todaysDate) - (sundaysLeft + saturdaysLeft));
This code does at least one part you ask for. Instead of "end of next month" it simply works with a given number of days.
$dfrom = time();
$fourweeks = 7 * 4;
for ($i = 0; $i < $fourweeks; $i ++) {
$stamp = $dfrom + ($i * 24 * 60 * 60);
$weekday = date("D", $stamp);
if (in_array($weekday, array("Mon", "Tue", "Wed", "Thu", "Fri"))) {
print date(DATE_RSS, $stamp) . "\n";
}
}
// Find today's day of the month (i.e. 15)
$today = intval(date('d'));
// Define the array that will hold the work days.
$work_days = array()
// Find this month's last day. (i.e. 30)
$last = intval(date('d', strtotime('last day of this month')));
// Loop through all of the days between today and the last day of the month (i.e. 15 through 30)
for ( $i = $today; $i <= $last; $i++ )
{
// Create a timestamp.
$timestamp = mktime(null, null, null, null, $i);
// If the day of the week is greater than Sunday (0) but less than Saturday (6), add the timestamp to an array.
if ( intval(date('w', $timestamp)) > 0 && intval(date('w', $timestamp)) < 6 )
$work_days[] = mktime($timestamp);
}
The $work_days array will contain timestamps which you could use this way:
echo date('Y-m-d', $work_days[0]);
The code above with work in PHP 4 as well as PHP 5. It does not rely on the functionality of the DateTime class which was not available until PHP 5.2 and does not require the use of "libraries" created by other people.

Easy way to get day number of current quarter?

PHP provides ways to get the number of the current day of the month (date('j')) as well as the number of the current day of the year (date('z')). Is there a way to get the number of the current day of the current quarter?
So right now, August 5, it is day 36 of the third quarter.
If there is no standard way of calculating this, does anyone have a (prefereably PHP-based) algorithm handy?
How about:
$curMonth = date("m", time());
$curQuarter = ceil($curMonth/3);
I wrote a class with the following methods. Enjoy.
public static function getQuarterByMonth($monthNumber) {
return floor(($monthNumber - 1) / 3) + 1;
}
public static function getQuarterDay($monthNumber, $dayNumber, $yearNumber) {
$quarterDayNumber = 0;
$dayCountByMonth = array();
$startMonthNumber = ((self::getQuarterByMonth($monthNumber) - 1) * 3) + 1;
// Calculate the number of days in each month.
for ($i=1; $i<=12; $i++) {
$dayCountByMonth[$i] = date("t", strtotime($yearNumber . "-" . $i . "-01"));
}
for ($i=$startMonthNumber; $i<=$monthNumber-1; $i++) {
$quarterDayNumber += $dayCountByMonth[$i];
}
$quarterDayNumber += $dayNumber;
return $quarterDayNumber;
}
public static function getCurrentQuarterDay() {
return self::getQuarterDay(date('n'), date('j'), date('Y'));
}
function date_quarter()
{
return ceil(date('n', time()) / 3);
}
or
function date_quarter()
{
$month = date('n');
if ($month <= 3) return 1;
if ($month <= 6) return 2;
if ($month <= 9) return 3;
return 4;
}
You can use Carbon it has easy modifiers for getFirstOf{Month,Year,Quarter}()
<?php
//take current date
$now = Carbon\Carbon::now();
//modify a copy of it to the first day of the current quarter
$firstOfQuarter = $now->copy()->firstOfQuarter();
//calculate the difference in days and add 1 to correct the index
$dayOfQuarter = $now->diffInDays($firstOfQuarter) + 1;
Assuming you mean a calendar-quarter (because a company fiscal year can start in any month of the year), you could rely on the date('z') to determine the day-of-year, and then keep a simple array of the day each quarter starts on:
$quarterStartDays = array( 1 /* Jan 1 */, 90 /* Mar 1, non leap-year */, ... );
Then with the current day-of-year you can first locate the largest start-day that's less than or equal to the day-of-year, then subtract.
Note that you need different numbers depending on the leap year.
<?php
function day_of_quarter($ts=null) {
if( is_null($ts) ) $ts=time();
$d=date('d', $ts);
$m=date('m', $ts)-1;
while($m%3!=0) {
$lastmonth=mktime(0, 0, 0, $m, date("d", $ts), date("Y",$ts));
$d += date('t', $lastmonth);
$m--;
}
return $d;
}
echo day_of_quarter(mktime(0, 0, 0, 1, 1,2009));
echo "\n";
echo day_of_quarter(time());
echo "\n";
?>
We need to calculate the date of the first quarter first
$current_month = date('m');
// Get first month of quarter
$new_month = (3 * floor(($current_month - 1 ) / 3)) + 1;
// Add prefix zero if needed
$new_month = substr('0' . $new_month, -2);
$first_quarter_day_date = date('Y') . '-' . $new_month . '-01';
next we calculate the http://php.net/manual/en/datetime.diff.php
$datetime1 = new DateTime($first_quarter_day_date);
$datetime2 = new DateTime();
$interval = $datetime1->diff($datetime2);
echo $interval->format('%a days');
<?php
function quarter_day($time = "") {
$time = $time ? strtotime($time) : time();
$date = intval(date("j", $time));
$month = intval(date("n", $time));
$year = intval(date("Y", $time));
// get selected quarter as number between 1 and 4
$quarter = ceil($month / 3);
// get first month of current quarter as number between 1 and 12
$fmonth = $quarter + (($quarter - 1) * 2);
// map days in a year by month
$map = [31,28,31,30,31,30,31,31,30,31,30,31];
// check if year is leap
if (((($year % 4) == 0) && ((($year % 100) != 0) || (($year % 400) == 0)))) $map[1] = 29;
// get total number of days in selected quarter, by summing the relative portion of $map array
$total = array_sum(array_slice($map, ($fmonth - 1), 3));
// get number of days passed in selected quarter, by summing the relative portion of $map array
$map[$month-1] = $date;
$day = array_sum(array_slice($map, ($fmonth - 1), ($month - $fmonth + 1)));
return "Day $day on $total of quarter $quarter, $year.";
}
print(quarter_day("2017-01-01")) . "\n"; // prints Day 1 on 90 of quarter 1, 2017.
print(quarter_day("2017-04-01")) . "\n"; // prints Day 1 on 91 of quarter 2, 2017.
print(quarter_day("2017-08-15")) . "\n"; // prints Day 46 on 92 of quarter 3, 2017.
print(quarter_day("2017-12-31")) . "\n"; // prints Day 92 on 92 of quarter 4, 2017.
I've noticed that this thread went a bit beyond the question, and it's the first response to many google searches with "Quarter" & "PHP" in them.
If you're working with the ISO standards of organization, which you should if you're doing a business app, then
$curMonth = date("m", time());
$curQuarter = ceil($curMonth/3);
Is NOT correct, because the first day of a year in the ISO standards, can be 30, or 31 December.
Instead, you should use this :
$current_yearly_cycle_year_number = 2019;
$current_yearly_cycle_start->setISODate( $current_yearly_cycle_year_number, 1, 1 );
$current_yearly_cycle_end->setISODate( $current_yearly_cycle_year_number, 53, 1 );
if( $current_yearly_cycle_end->format("W") !== "53" )
$current_yearly_cycle_end->setISODate( $current_yearly_cycle_year_number, 52, 1 );
$week_number_start = intval( $current_yearly_cycle_start->format( "W" ) );
$timestamp_start_quarter = ( $week_number_start === 1 ? 1 : intval( ceil( $current_yearly_cycle_start->format( "m" ) / 3 ) ) );
var_dump( $timestamp_start_quarter );

Categories