I was looking for a plugin that allowed only paid members to access certain WP pages and to display the content based on their day of the course (the course is 200 days long). I used PaidMembershipsPro, but I had to modify it to my needs and I post it here in case might be useful for someone else.
If someone buys a different "membership level" it extends it instead of overwriting (I had to make 3 levels for 3 payment plans, 1/3/6 months, I named them all the same but if someone buys 3 months and then another month it reset the duration, so there is a filter for it below). I asked on SO already, but I didn't get an answer, so I wrote the functions myself. It might be bit sloppy though.
the table:
tt_subs s_id(int) s_user(int) s_months(int) s_since(timestamp)
This is the function that puts the data into a table (it takes the duration as days, because all my levels were timed in days)
add_action("pmpro_after_checkout", tt_AddToSubs);
function tt_AddToSubs($user_id){
global $wpdb, $current_user;
$days = $current_user->data->membership_level->expiration_number; //get days from current order
$months = ceil($days/30);
$today = date('Y-m-d H:i:s',strtotime('today midnight'));
$result = $wpdb->get_results("SELECT s_user, s_months, s_since FROM tt_subs WHERE s_user = $user_id", ARRAY_A);
$rowCount = $wpdb->num_rows;
if($rowCount == 0)//if it's a new user
{
$wpdb->insert('tt_subs',array('s_user' => $user_id,
's_months' => $months,'s_since' => $today),
array('%s','%d','%s')
);
}
else
{
$sincedays = ($result[0]['s_months']*30); //counted without the new month
$since = strtotime("-$sincedays days", strtotime('today midnight'));
$newsince = (strtotime($result[0]['s_since']) <= $since ? $since : strtotime($result[0]['s_since'])); //if membership has passed, shift s_since so user is back in his day
$newsince = date('Y-m-d H:i:s', $newsince);
$months += $result[0]['s_months']; //add months to the existing ones
$wpdb->update('tt_subs',
array('s_months' => $months,'s_since' => $newsince),
array( 's_user' => $user_id ), //where array(
'%d', // value1
'%s' // value2
),
array( '%d' ) //where format
);
}
}
this is a filter that I found for extending the memberships instead of overwriting them
add_filter("pmpro_checkout_level", "level_extend_memberships");
function level_extend_memberships($level)
{
global $pmpro_msg, $pmpro_msgt, $current_user;
//does this level expire? are they an existing members with an expiration date?
if(!empty($level) && !empty($level->expiration_number) && pmpro_hasMembershipLevel() && !empty($current_user->membership_level->enddate))
{
//get the current enddate of their membership
$expiration_date = $current_user->membership_level->enddate;
//calculate days left
$todays_date = time();
$time_left = $expiration_date - $todays_date;
//time left?
if($time_left > 0)
{
//convert to days and add to the expiration date (assumes expiration was 1 year)
$days_left = floor($time_left/(60*60*24));
//figure out days based on period
if($level->expiration_period == "Day")
$total_days = $days_left + $level->expiration_number;
elseif($level->expiration_period == "Week")
$total_days = $days_left + $level->expiration_number * 7;
elseif($level->expiration_period == "Month")
$total_days = $days_left + $level->expiration_number * 30;
elseif($level->expiration_period == "Year")
$total_days = $days_left + $level->expiration_number * 365;
//update number and period
$level->expiration_number = $total_days;
$level->expiration_period = "Day";
}
}
return $level;
}
and finally a function that returns the day the user is on
function tt_myDay()
{
global $wpdb;
if(current_user_can('add_users'))
{
return 999;
}
else
{
$resultq = $wpdb->get_results("SELECT s_since, s_months FROM tt_subs WHERE s_user = ".get_current_user_id(), ARRAY_A);
$day = ceil((time() - strtotime($resultq[0]['s_since']))/86400);
return ($day > ($resultq[0]['s_months']*30) ? ($resultq[0]['s_months']*30) : $day );
}
}
Related
I have to create a scheduling component that will plan e-mails that need to be sent out. Users can select a start time, end time, and frequency. Code should produce a random moment for every frequency, between start and end time. Outside of office hours.
Paramaters:
User can select a period between 01/01/2020 (the start) and 01/01/2021 (the end). In this case user selects a timespan of one exactly year.
User can select a frequency. In this case user selects '2 months'.
Function:
Code produces a list of datetimes. The total time (one year) is divided by frequency (2 months). We expect a list of 6 datetimes.
Every datetime is a random moment in said frequency (2 months). Within office hours.
Result:
An example result for these paramaters might as follows, with the calculated frequency bounds for clarity:
[jan/feb] 21-02-2020 11.36
[mrt/apr] 04-03-2020 16.11
[mei/jun] 13-05-2020 09.49
[jul-aug] 14-07-2020 15.25
[sep-okt] 02-09-2020 14.09
[nov-dec] 25-12-2020 13.55
--
I've been thinking about how to implement this best, but I can't figure out an elegant solution.
How could one do this using PHP?
Any insights, references, or code spikes would be greatly appreciated. I'm really stuck on this one.
I think you're just asking for suggestions on how to generate a list of repeating (2 weekly) dates with a random time between say 9am and 5pm? Is that right?
If so - something like this (untested, pseudo code) might be a starting point:
$start = new Datetime('1st January 2021');
$end = new Datetime('1st July 2021');
$day_start = 9;
$day_end = 17;
$date = $start;
$dates = [$date]; // Start date into array
while($date < $end) {
$new_date = clone($date->modify("+ 2 weeks"));
$new_date->setTime(mt_rand($day_start, $day_end), mt_rand(0, 59));
$dates[] = $new_date;
}
var_dump($dates);
Steve's anwser seems good, but you should consider 2 additional things
holiday check, in the while after first $new_date line, like:
$holiday = array('2021-01-01', '2021-01-06', '2021-12-25');
if (!in_array($new_date,$holiday))
also a check if date is a office day or a weekend in a similar way as above with working days as an array.
It's kind of crappy code but I think it will work as you wish.
function getDiffInSeconds(\DateTime $start, \DateTime $end) : int
{
$startTimestamp = $start->getTimestamp();
$endTimestamp = $end->getTimestamp();
return $endTimestamp - $startTimestamp;
}
function getShiftData(\DateTime $start, \DateTime $end) : array
{
$shiftStartHour = \DateTime::createFromFormat('H:i:s', $start->format('H:i:s'));
$shiftEndHour = \DateTime::createFromFormat('H:i:s', $end->format('H:i:s'));
$shiftInSeconds = intval($shiftEndHour->getTimestamp() - $shiftStartHour->getTimestamp());
return [
$shiftStartHour,
$shiftEndHour,
$shiftInSeconds,
];
}
function dayIsWeekendOrHoliday(\DateTime $date, array $holidays = []) : bool
{
$weekendDayIndexes = [
0 => 'Sunday',
6 => 'Saturday',
];
$dayOfWeek = $date->format('w');
if (empty($holidays)) {
$dayIsWeekendOrHoliday = isset($weekendDayIndexes[$dayOfWeek]);
} else {
$dayMonthDate = $date->format('d/m');
$dayMonthYearDate = $date->format('d/m/Y');
$dayIsWeekendOrHoliday = (isset($weekendDayIndexes[$dayOfWeek]) || isset($holidays[$dayMonthDate]) || isset($holidays[$dayMonthYearDate]));
}
return $dayIsWeekendOrHoliday;
}
function getScheduleDates(\DateTime $start, \DateTime $end, int $frequencyInSeconds) : array
{
if ($frequencyInSeconds < (24 * 60 * 60)) {
throw new \InvalidArgumentException('Frequency must be bigger than one day');
}
$diffInSeconds = getDiffInSeconds($start, $end);
// If difference between $start and $end is bigger than two days
if ($diffInSeconds > (2 * 24 * 60 * 60)) {
// If difference is bigger than 2 days we add 1 day to start and subtract 1 day from end
$start->modify('+1 day');
$end->modify('-1 day');
// Getting new $diffInSeconds after $start and $end changes
$diffInSeconds = getDiffInSeconds($start, $end);
}
if ($frequencyInSeconds > $diffInSeconds) {
throw new \InvalidArgumentException('Frequency is bigger than difference between dates');
}
$holidays = [
'01/01' => 'New Year',
'18/04/2020' => 'Easter 1st official holiday because 19/04/2020',
'20/04/2020' => 'Easter',
'21/04/2020' => 'Easter 2nd day',
'27/04' => 'Konings',
'04/05' => '4mei',
'05/05' => '4mei',
'24/12' => 'Christmas 1st day',
'25/12' => 'Christmas 2nd day',
'26/12' => 'Christmas 3nd day',
'27/12' => 'Christmas 3rd day',
'31/12' => 'Old Year'
];
[$shiftStartHour, $shiftEndHour, $shiftInSeconds] = getShiftData($start, $end);
$amountOfNotifications = floor($diffInSeconds / $frequencyInSeconds);
$periodInSeconds = intval($diffInSeconds / $amountOfNotifications);
$maxDaysBetweenNotifications = intval($periodInSeconds / (24 * 60 * 60));
// If $maxDaysBetweenNotifications is equals to 1 then we have to change $periodInSeconds to amount of seconds for one day
if ($maxDaysBetweenNotifications === 1) {
$periodInSeconds = (24 * 60 * 60);
}
$dates = [];
for ($i = 0; $i < $amountOfNotifications; $i++) {
$periodStart = clone $start;
$periodStart->setTimestamp($start->getTimestamp() + ($i * $periodInSeconds));
$seconds = mt_rand(0, $shiftInSeconds);
// If $maxDaysBetweenNotifications is equals to 1 then we have to check only one day without loop through the dates
if ($maxDaysBetweenNotifications === 1) {
$interval = new \DateInterval('P' . $maxDaysBetweenNotifications . 'DT' . $seconds . 'S');
$date = clone $periodStart;
$date->add($interval);
$dayIsWeekendOrHoliday = dayIsWeekendOrHoliday($date, $holidays);
} else {
// When $maxDaysBetweenNotifications we have to loop through the dates to pick them
$loopsCount = 0;
$maxLoops = 3; // Max loops before breaking and skipping the period
do {
$day = mt_rand(0, $maxDaysBetweenNotifications);
$periodStart->modify($shiftStartHour);
$interval = new \DateInterval('P' . $day . 'DT' . $seconds . 'S');
$date = clone $periodStart;
$date->add($interval);
$dayIsWeekendOrHoliday = dayIsWeekendOrHoliday($date, $holidays);
// If the day is weekend or holiday then we have to increment $loopsCount by 1 for each loop
if ($dayIsWeekendOrHoliday === true) {
$loopsCount++;
// If $loopsCount is equals to $maxLoops then we have to break the loop
if ($loopsCount === $maxLoops) {
break;
}
}
} while ($dayIsWeekendOrHoliday);
}
// Adds the date to $dates only if the day is not a weekend day and holiday
if ($dayIsWeekendOrHoliday === false) {
$dates[] = $date;
}
}
return $dates;
}
$start = new \DateTime('2020-12-30 08:00:00', new \DateTimeZone('Europe/Sofia'));
$end = new \DateTime('2021-01-18 17:00:00', new \DateTimeZone('Europe/Sofia'));
$frequencyInSeconds = 86400; // 1 day
$dates = getScheduleDates($start, $end, $frequencyInSeconds);
var_dump($dates);
You have to pass $start, $end and $frequencyInSeconds as I showed in example and then you will get your random dates. Notice that I $start and $end must have hours in them because they are used as start and end hours for shifts. Because the rule is to return a date within a shift time only in working days. Also you have to provide frequency in seconds - you can calculate them outside the function or you can change it to calculate them inside. I did it this way because I don't know what are your predefined periods.
This function returns an array of \DateTime() instances so you can do whatever you want with them.
UPDATE 08/01/2020:
Holidays now are part of calculation and they will be excluded from returned dates if they are passed when you are calling the function. You can pass them in d/m and d/m/Y formats because of holidays like Easter and in case when the holiday is on weekend but people will get additional dayoff during the working week.
UPDATE 13/01/2020:
I've made updated code version to fix the issue with infinite loops when $frequencyInSeconds is shorter like 1 day. The new code used few functions getDiffInSeconds, getShiftData and dayIsWeekendOrHoliday as helper methods to reduce code duplication and cleaner and more readable code
I am looking for some basic attendance logic. What I have done so far is that employees can click on two different kinds of buttons and mark themselves as Signed In, Signed Out (status 1 and 2) using one button and Break Start, Break Over (status 3 and 4) using the other button.
Now when I calculate employee's total Sign In hours and total Break hours for a particular date I do something like below.
First iterate over a loop of Starting date and Ending date for which I want to see the working hours.
Now first of all check if the employee logged in on a particular date, by finding a status 1 entry of that date.
If the employee logged in on that date, then I fetch all attendance records for that date.
Now I iterate over this date's attendance records add up the time differences starting from first status 1 (i.e. Login) to next status and from next status (which can be either a break start 3 or a log out 2) till the next status (which can be either break over 4 or log in 1).
This is working good and my working hours' calculations are coming fine.
There is however one logical part that I am not able to understand i.e. if the employee does not logout on the same date for which I have fetched out the records, then the time span from last login or break start till the logout are not getting calculated. Because the final logged out status does not fall on the same date for which I fetched the records.
So, I need some help in understanding any suggestions how this can be managed and how can I calculate the working hours if the employee's logout status falls on a different date than login date.
Thanks in advance.
Here is some code.
public function getEmployeeAttendance($company_uid , $emp_uid)
{
for($m=1; $m<=12; $m++)
{
$mon = strtotime(date('Y-' . $m . '-00'));
$first = date("Y-m-01", $mon); // First Date Of cuRRENT mONTH
$last = date("Y-m-t", $mon); // Last Date Of cuRRENT mONTH
$date[] = range_date($first, $last);
}
$atten = array();
//echo "<pre>";
foreach($date as $dt)
{
foreach($dt as $d)
{
// A function to check if there was a status 1 on this date
$myAttendance = $this->Attendance_Model->myAttendance($company_uid , $emp_uid, $d);
# If Employee Signed In on This Date (i.e. Status was 1)
if(count($myAttendance) >0)
{
# Calculate Working Hours
$attenRec = $this->Attendance_Model->getAttendanceRecords($company_uid , $emp_uid, $d);
$signInHrs = 0;
$breakHrs = 0;
$workingHrs = 0;
for($i=0; $i<count($attenRec); $i++)
{
// Get this record's status
$status = $attenRec[$i]['status'];
// Get next record's status
if(!empty($attenRec[$i + 1]))
{
if($status == '1' || $status == '4') // Sign In or Break Over
{
$thisTime = strtotime($attenRec[$i]['atten_time']);
$nextTime = strtotime($attenRec[$i + 1]['atten_time']);
$diff = round(($nextTime - $thisTime) / 3600, 2);
$signInHrs += $diff;
}
if($status == '3') // Break Start
{
$thisTime = strtotime($attenRec[$i]['atten_time']);
$nextTime = strtotime($attenRec[$i + 1]['atten_time']);
$diff = round(($nextTime - $thisTime) / 3600, 2);
$signInHrs += $diff;
$breakHrs += $diff;
}
}
}
$onlySignInHrs = floor($signInHrs);
$remainingSignInHrs = $signInHrs - $onlySignInHrs;
$signInMinutes = round($remainingSignInHrs * 60);
$myAttendance['signInHrs'] = $onlySignInHrs . " Hrs : " . $signInMinutes . " Min";
$onlyBreakHrs = floor($breakHrs);
$remainingBreakHrs = $breakHrs - $onlyBreakHrs;
$breakMinutes = round($remainingBreakHrs * 60);
$myAttendance['breakHrs'] = $onlyBreakHrs . " Hrs : " . $breakMinutes . " Min";
$workingHrs = $signInHrs - $breakHrs;
$onlyWorkingHrs = floor($workingHrs);
$remainingWorkingHrs = $workingHrs - $onlyWorkingHrs;
$workingMinutes = round($remainingWorkingHrs * 60);
$myAttendance['workingHrs'] = $onlyWorkingHrs . " Hrs : " . $workingMinutes . " Min";
}
# Save This Date's Attendance
$atten[] = $myAttendance;
}
}
return $atten;
}
I am trying to create a booking form where a user can select a booking time between 2 given times in 5 minute intervals. For example I want time slots between 10am and 12pm which would give me about 20 time slots.
When the user goes to select a slot, the earliest slot should be at least 15 mins ahead of the current time but the user can select a slot and hour or more if desired.
I found some code on SO (can't remember where) and I've edited it for my needs and it works if the current time is within the start and end time but if the current time is an hour before the earliest time, it doesn't create the time slots.
I know why it does it but i don't know how to fix it. It has to do with the while condition.
I would like to be able to book a slot hours before the first available slot if that is possible.
$timenow = time();
$start_time = strtotime('+15 minutes', $timenow);
// round to next 15 minutes (15 * 60 seconds)
$start_time = ceil($start_time / (5 * 60)) * (5 * 60);
//set the start times
$opentime = strtotime('10:00');
$closetime = strtotime('11:55');
// get a list of prebooked slots from database
$time_slots = $this->countStartTimes();
$available_slots = array();
while($start_time <= $closetime && $start_time >= $opentime) {
$key = date('H:i', $start_time);
if(array_key_exists($key, $time_slots)) {
if($time_slots[$key] == SLOTS) {
$available_slots[] = 'FULL';
break;
}
}
$available_slots[] = date('H:i', $start_time);
$start_time = strtotime('+5 minutes', $start_time);
}
I managed to get it working using Datetime()
$timenow = new DateTime(date('H:i'));
$timenow->add(new DateInterval('PT15M'));
$start = new DateTime('11:00');
$end = new DateTime('14:00');
$interval = new DateInterval('PT5M');
$time_slots = $this->countStartTimes();
$available_slots = array();
$period = new DatePeriod($start, $interval, $end);
foreach($period as $time) {
$timeslot = $time->format('H:i');
if ($timenow > $time) {
continue;
}
if(array_key_exists($timeslot, $time_slots)) {
if($time_slots[$timeslot] == SLOTS) {
$available_slots[] = array('key' => $timeslot, 'value' => 'FULL');
continue;
}
}
$available_slots[] = array('key' => $timeslot, 'value' => $timeslot);
}
Carbon has all of the functions inherited from the base DateTime class. This approach allows you to access the base functionality if you see anything missing in Carbon but is there in DateTime.
// Carbon::diffInYears(Carbon $dt = null, $abs = true)
echo Carbon::now('America/Vancouver')->diffInSeconds(Carbon::now('Europe/London')); // 0
$dtOttawa = Carbon::createFromDate(2000, 1, 1, 'America/Toronto');
$dtVancouver = Carbon::createFromDate(2000, 1, 1, 'America/Vancouver');
echo $dtOttawa->diffInHours($dtVancouver); // 3
echo $dtOttawa->diffInHours($dtVancouver, false); // 3
echo $dtVancouver->diffInHours($dtOttawa, false);
Use carbon class for this it really help you
Starting with the number 9 and using php, I would like to be able to count up from there, and echo out the next number in increments of 1.
So, number 9, then after 1 month the number would change to 10, then another month 11, then 12 etc., with no maximum number/stop point.
How can I accomplish this? So far I have the below code.
$number = 9;
$output = $number + 1;
echo $output;
Is there a way to set this to increase once a month?
You can do this with the PHP date()-function. This is one example of doing it if you are not dependent on the day of the month, but adding day functionality is possible and should be quit easy.
$startNumber = 9;
$startYear = 2015;
$startMonth = 9;
$currentYear = intval( date( "Y" ) );
$currentMonth = intval( date( "n" ) );
$monthsToAdd = ( ( $currentYear - $startYear ) * 12 )
+ ( $currentMonth - $startMonth );
echo $startNumber + $monthsToAdd;
From your question, I'd say:
$number = 9;
$output = date('n') + $number;
echo $output;
But that depends on what you are trying to accomplish. You can also wrap the number around the date() with a modulo.
However this is nothing random. If you want to create a random number every month like your topic suggests, use the month as the random seed.
srand(date('n'));
$number = rand();
a very inefficient way would be
<?php
function increm($duration){
while ($i<$duration) {
$i++;
}
return true;
}
$number = 9;
$start = time();
$i = 0;
while (1){
increm(3600*24*30);
$i++;
// Do your code
}
?>
this script would have to be run continuously for months.
A better way would be
<?php
$number = 9;
if(!file_exists('date.txt')){
$date=date('n');
file_put_contents( (string)time());
$date = 0;
}
else{
$date= file_get_contents('date.txt');
$date= date()-(int)$date;
$date= floor($date/(24*3600*30));
}
// do whatever you may
?>
But this script would increase it whenever called as the first open date would be stored. Will work forever (till UNIX can timestamp).
for this purpose you have to store the number in the database, compare with current unix timestamp and update it when the new month is reached.
2 database columns: count_month int(10) and next_month int(10) where next_month will contain the unix timestamp of the first day of the next month. you can run it with cronjobs or on production.
<?php
$now = strtotime("now");
$next_month = strtotime("first day of next month");
if ($query = $dbconnect->prepare("SELECT next_month FROM table1")) {
$query->execute();
$query->bind_result($compare_time);
$query->store_result();
$row_count = $query->num_rows;
if ($row_count > 0) {
while ($query->fetch()) {
if ($compare_time < $now) { // you reached the 1th of the next month time to update
if ($query2 = $dbconnect->prepare("UPDATE table1 SET count_month=count_month +1, next_month=?")) {
$query2->bind_param('i', $next_month);
$query2->execute();
$query2->close();
}
}
}
}
$query->free_result();
$query->close();
}
?>
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") . "!";