This question already has answers here:
How to find first day of the next month and remaining days till this date with PHP
(17 answers)
Closed 2 years ago.
I am working with WooCommerce Subscriptions and am trying to set it so that users can select their own start date using another plugin. Within the date picker plugin, if a user chooses a date within the middle of the month, the payments are supposed to be prorated and then the subscription starts on the first day of the next month. However, the plugin works to only start at the day the subscription starts. I am trying to adjust this so it chooses the start date of the first day of the next month. I have used this as reference - How to find first day of the next month and remaining days till this date with PHP
function woosubscriptions_custom_cart_next_payment_date( $start_pay_date , $recurring_cart){
foreach($recurring_cart->get_cart() as $cart_item_key => $cart_item){
if(isset($cart_item['start-subcription']) && !empty($cart_item['start-subcription'])){
$days_free_trial = WC_Subscriptions_Product::get_trial_length( $cart_item['data'] );
$start_subcription = $cart_item['start-subcription'];
if($days_free_trial > 0){
$start_subcription .= ' ' . $days_free_trial . ' days';
}
$offset=5*60*60; //converting 5 hours to seconds.
$start_pay_date = gmdate( 'Y-m-d H:i:s', strtotime($start_subcription) + $offset);
$first_day_next_month = ($start_pay_date, strtotime('first day of next month'));
break;
}
}
return $first_day_next_month;
}
add_filter( 'wcs_recurring_cart_next_payment_date', 'woosubscriptions_custom_cart_next_payment_date', 10 , 2);
It is not correctly getting the first day of next month.
Your code to calculate the first day of next month is not quite right. The answer you have linked looks different to the code you have used.
strtotime('first day of next month') calculates the first day of the current month and will bear no relation to the start date.
You could use a DateTime object and figure it out from there:
$start_pay_date = new DateTime($start_subcription);
$first_day_next_month = $start_pay_date->modify("first day of next month");
$first_day_next_month would then represent the first day of the month after your $start_pay_date, you can use any of the DateTime methods to then format it how you want (e.g. $first_day_next_month->format("Y-m-d"))
Related
I would like to determine the current Fiscal week period and year with a function when you pass it an empty argument, or the week, period and year of a datestring you include in the argument.
I have a function like this so far.
function FiscalDates($date){
$basedate=date_create("2018-04-29");
$querydate=date_create($date);
$diff=date_diff($basedate,$querydate);
$days = $diff->format('%a');
if(fmod($days,7)==0){
$weekno = ($days/7)+1;
} else {
$weekno = ceil($days/7);
}
if(fmod($weekno,4)==0){
$period = ($weekno/4);
} else {
$period = ceil($weekno/4);
}
if(fmod($period,13)==0){
$year = ($period/13)-1;
} else {
$year = (ceil($period/13))-1;
}
$period = $period-(13*$year);
$year = $year+2018;
return array($weekno,$period,$year);
}
This works for the most part, but the only problem is that it does not account for the 'leap week' that happens every 5-6 years. (Where there is 53 weeks in the year) see 2nd paragraph of this page about that. Every time this happens, the calculations will be off by another week.
How can I achieve a similar thing, but account for the 53 weeks in a year years and keep it accurate?
Might be too late or not exactly a direct reply, but had similar issues a few years back for a UK business, so decided to work on a library that could prove helpful for you.
https://github.com/RoussKS/financial-year
It can get period/weeks for a financial year.
It handles 2 types of financial year. The standard 12 month (period) one, named calendar as a library convention, and business for 13 period financial years (for 52/53 weeks). Business is the one you would want to use.
It does not check when a year should be a 53 week year as this depends on the business, so you would need to provide that as a param (defaults to false aka 52).
Example use to fetch the period & week
require_once __DIR__ . '/vendor/autoload.php';
// DateTimeAdapter
// If instantiating with string, it must be of ISO-8601 format 'YYYY-MM-DD'.
// This is your business's financial year start date.
$startDate = new \DateTime('2018-04-01');
$fy = new \RoussKS\FinancialYear\DateTimeAdapter('business', $startDate, false); // false for 52 weeks, true for 53 weeks
$dateToExamine = '2018-04-29';
// Get period of the date in question
echo $fy->getPeriodIdByDate($dateToExamine); // 1
// Get week of the date in question
echo $fy->getBusinessWeekIdIdByDate($dateToExamine); // 5
Not sure though what you mean by year, is it like naming the year as per 2018/2019?
The goal is exclusively to get a range of days, in other words
, start date and end date, as if it were a "calendar matrix", containing the 42 days, being the days of the current month, with the days of the previous month and next month. No need to present (render) a calendar, only get dates.
For example, follow image below.
I need to enter a certain month of a given year, and would need to get this range of days, as picture.
Using PHP Carbon, I easily get the days of the current month, using startOfMonth(), endOfMonth() , subMonth(), addMonth().
Doing this, I get every day of these 3 months, but the goal is to be able to "filter" these days to present only the interval equal to a calendar, but obviously something dynamic, ie, if I use Carbon, would simply inform the desired date , and get "filtered" range, respecting the position of each "cell".
$prev_start = Carbon::now()->subMonth()->startOfMonth();
$prev_end = Carbon::now()->subMonth()->endOfMonth();
$start = Carbon::now()->startOfMonth();
$end = Carbon::now()->endOfMonth();
$next_start = Carbon::now()->addMonth()->startOfMonth();
$next_end = Carbon::now()->addMonth()->endOfMonth();
So here's what you can do:
$monthStart = Carbon::now()->startOfMonth();
$monthEnd = Carbon::now()->endOfMonth();
$calendarStart = $monthStart->startOfWeek(Carbon::SUNDAY);
$calendarEnd = $monthEnd->endOfWeek(Carbon::SATURDAY);
$calendarStart and $calendarEnd should now contain the first and last day that will be displayed in a single screen. This assumes that the calendar will expand the first and last week displayed.
If you are using a calendar that always shows 42 days regardless you can just do:
$monthStart = Carbon::now()->startOfMonth();
$calendarStart = $monthStart->startOfWeek(Carbon::SUNDAY);
$calendarEnd = $calendarStart->addDay(42);
I am struggling with the price calculation of Woocommerce Bookings for the type "days". If the price on a daterange (e.g. Monday to Wednesday or Wednesday-Saturday or Sunday-Tuesday...) is higher than on the other days.
So far I know how many days:
$days = date_diff($from, $to)->format('%d');
This question helps to get the number of single days: calculate sundays between two dates
But how do I get not only "sundays" but every daterange (e.g. from 6 to 2) with this:
$sundays = intval($days / 7) + ($from->format('N') + $days % 7 >= 7);
I guess I need to iterate through daterange and use this formula but I cannot figure out how.
You can use a completely different approach:
Create a DatePeriod object and loop through the Period object and increment a variable each time you encounter the range.
The following code achieve it but only return the number of complete range:
$from='2018/09/1';
$to='2018/09/31';
$start='Sunday';
$end='Thursday';
$go=false;
$period=new DatePeriod(date_create($from),date_interval_create_from_date_string('1 days'),date_create($to));
$nRange=0;
foreach($period as $date){
if($date->format('l')===$start){
$go=true;
}
if($go&&$date->format('l')===$end){
$go=false;
$nRange++;
}
}
print_r($nRange);
output :
4
It works fine for any chosen range.
However if the need is to get any valid day within the given range complete or not you can alter the previous code this way:
$from='2018/09/17';
$to='2018/09/31';
$start='Sunday';
$end='Thursday';
$day_num=['Monday'=>1,'Tuesday'=>2,'Wednesday'=>3,'Thursday'=>4,'Friday'=>5,'Saturday'=>6,'Sunday'=>7];
$start_num=$day_num[$start];
$end_num=$day_num[$end];
$period=new DatePeriod(date_create($from),date_interval_create_from_date_string('1 days'),date_create($to));
$nRange=0;
if($start_num===$end_num){
$valid_range=array_values($day_num);//keep the number of each day of the week
}
elseif($start_num>$end_num){
$valid_range=array_values($day_num);//keep the number of each day of the week
while($valid_range[0]!==$start_num){//rotate the values to keep the start day first
$pop=array_shift($valid_range);
array_push($valid_range,$pop);
}
$valid_range=array_slice($valid_range,array_search($start_num,$valid_range),$start_num-$end_num);//keep only the days in the chosen range
}else{
$valid_range=array_values($day_num);//keep the number of each day of the week
$valid_range=array_slice($valid_range,array_search($start_num,$valid_range),$end_num-$start_num); //keep only the days in the chosen range
}
$valid_range=array_flip($valid_range);//flip the array to make the search more fast
foreach($period as $date){
if(isset($valid_range[(int)$date->format('N')])){
$nRange++;
}
}
print_r($nRange);//output the number of valid days
ouput:
6
I tried this:
$d=cal_days_in_month(CAL_GREGORIAN,4,2016);
echo $d;
$d gives=>30
Which is current day for this month and year for 2016. Here I have given month and year manually. How do I bring automatically for every year.Is there any function like this. my objective is I want to know how many days in a month.
Use
for($i=1;$i<= 12;$i++)
{
$d=cal_days_in_month(CAL_GREGORIAN,$i ,2016);
echo $i.' -> '.$d;
}
It should work .
I have written some code where I have a start date and number of days duration and then get an end date ie start date 18th December, duration 21 days, end date 8th January. However I want to push the end date forward to avoid certain holidays (25th December through to 6th January) so that the end date becomes 15th January. All the answers I have seen include how to calculate business days and take out weekends, which I don't need. I just want to be able to define specific holidays in an array, get it to see if the holiday is within the start date and end date and if it is move the end date forward by that number of days.
Oh, then the date needs to be inserted into a database. Thanks.
Iterate through the $holidays array. If a holiday is in the given range, then move end date one day in the future:
$startDate = new DateTime('2015-12-18');
$endDate = new DateTime('2016-01-08');
// $holidays array must be sorted. if not, then sort it first
$holidays = array("2015-12-25","2015-12-26","2016-01-01");
$newEndDate = $endDate;
foreach ($holidays as $holiday) {
$holidayDate = new DateTime($holiday);
if ($startDate <= $holidayDate && $holidayDate <= $newEndDate) {
// there is a holiday in the range
$newEndDate->add(new DateInterval('P1D'));
}
}
echo($newEndDate->format('Y-m-d'));
Thank you for all those that posted possible solutions. I solved the problem by adding a selector to the php page which adds 7, 14 or 21 days to the end date (the user sees this as 1 week, 2 weeks etc) and this solved the problem.