patternphpModerate
Calculate a month later than current month (without rolling over to next month)
Viewed 0 times
withoutlaterthanrollingnextcalculatecurrentmonthover
Problem
I needed a script for working out billing dates over a period of time. The date should be the same day every month however if the billing date starts on a date that doesn't exist in another month, then it should be on the last day of that month. This rules out the
Try as I might, I couldn't find anything in-built to accommodate for this, so I wrote the following, however it seems like a lot of code for what I'm trying to achieve so I was wondering if anyone could suggest a better / in-built way?
The top array and the lines that build the string are just for testing, but it still seems like a lot of code?
Also I have no idea how necessary my parenthesis are when creating ternary statements, and I do feel a bit ne
DateTimeInterval Object, because that causes months to 'rollover' (31/01 becomes 03/03 etc.) which is unacceptable for my use case.Try as I might, I couldn't find anything in-built to accommodate for this, so I wrote the following, however it seems like a lot of code for what I'm trying to achieve so I was wondering if anyone could suggest a better / in-built way?
$replaceVars = array(
'effectivedate' => '30-9-2014',
'vatpc' => 0.15,
'paymentamount' => 150.00,
'duration' => 12
);
$effectivedateObj = new DateTime($replaceVars['effectivedate']);
$iD = array(
'd' => $effectivedateObj->format('d'),
'm' => $effectivedateObj->format('m'),
'y' => $effectivedateObj->format('Y')
);
$payments = '';
for ($i=0; $i $iD['d'],
'm' => (($iD['m'] + $i) > 12) ? (($iD['m'] + $i) % 12) : $iD['m'] + $i,
'y' => (($iD['m'] + $i) > 12 ? $iD['y'] + 1 : $iD['y'])
);
if($newDate['d'] > cal_days_in_month(CAL_GREGORIAN, $newDate['m'], $newDate['y']))
{
$newDate['d'] = cal_days_in_month(CAL_GREGORIAN, $newDate['m'], $newDate['y']);
}
$paymentString = '';
$paymentString .= 'Payment Number '.($i+1).'';
$paymentString .= ''. $newDate['d'] .'/'. $newDate['m'] .'/'. $newDate['y'] .'';
$paymentString .= '£'. round(( $replaceVars['paymentamount'] + ( $replaceVars['paymentamount'] * $replaceVars['vatpc'] )), 2) .'';
$paymentString .= '';
$payments .= $paymentString;
echo $paymentString . '';
}The top array and the lines that build the string are just for testing, but it still seems like a lot of code?
Also I have no idea how necessary my parenthesis are when creating ternary statements, and I do feel a bit ne
Solution
I'm inclined to keep it simple:
This just checks to see if the month is the expected one, and if not, backs up one day at a time until it is. The advantage is that it's short, clear, and will work even in leap years (try 2004 to verify that).
Edit: It's also easy to make this into a user-defined function:
$start = new DateTime('30-Jan-2014', new DateTimeZone("America/Toronto"));
$end = clone $start;
$end->modify('+1 month');
while (($start->format('m')+1)%12 != $end->format('m')%12) {
$end->modify('-1 day');
}
echo $end->format('d-M-Y');This just checks to see if the month is the expected one, and if not, backs up one day at a time until it is. The advantage is that it's short, clear, and will work even in leap years (try 2004 to verify that).
Edit: It's also easy to make this into a user-defined function:
function addMonth($begin)
{
$end = clone $begin;
$end->modify('+1 month');
while (($begin->format('m')+1)%12 != $end->format('m')%12) {
$end->modify('-1 day');
}
return $end;
}Code Snippets
$start = new DateTime('30-Jan-2014', new DateTimeZone("America/Toronto"));
$end = clone $start;
$end->modify('+1 month');
while (($start->format('m')+1)%12 != $end->format('m')%12) {
$end->modify('-1 day');
}
echo $end->format('d-M-Y');function addMonth($begin)
{
$end = clone $begin;
$end->modify('+1 month');
while (($begin->format('m')+1)%12 != $end->format('m')%12) {
$end->modify('-1 day');
}
return $end;
}Context
StackExchange Code Review Q#46047, answer score: 10
Revisions (0)
No revisions yet.