Reputation: 95
So I am building an website app that calculates an amount due for a bill any user has. I managed to get all the calculations working great right up until the bills come due next month. Something went wrong with the calculations of how many paychecks a user gets before a bill is due. After a few var_dumps I realized that when adding the days to my loop I am coming up with an extra 3600 seconds (1 hour that is gained during daylight savings time on March 12th). So here is a peak at the code that calculates everything. Just for the people looking at this down the road months after this is posted. Todays current date is 2017-02-27
//declare paychecks as counter
$paychecks = 0;
//the number of days a user has between paychecks
$frequency = 14;
//users next payday
$next_payday = strtotime(2017-03-10);
//the date the next bill is due
$due_date = strtotime(2017-03-24);
In theory, there should be 2 paychecks before the due_date. (The 2nd paycheck happens the day the bill is due)
while ($next_payday <= $due_date) {
$payday = new DateTime($next_payday);
$date_array = $payday->add(new DateInterval('P'. $frequency . 'D'));
$next_payday += strtotime($date_array->format('Y-m-d'));
//I commented this out but this does not work either
//$next_payday += ($frequency * 86400);
//increase the counter
$paychecks++;
}
So in theory (And this works any other time other than when DST is a factor) I am trying to determine how many paychecks a user has before a bill is due. The problem is that this instance returns 1 instead of 2 because $next_payday actually gets an extra 3600 seconds added to it when the second iteration of the loop takes place. This makes $next_payday 3600 seconds higher than $due_dates value. I would assume because of DST.
So should I compare the string values (date('Y-m-d', $due_date) == date('Y-m-d', $next_payday)) instead? That would work when the due date is the same as the next payday, but will not work when the date is greater than or less than. I have noticed when converting those dates back to string format, they are the same. Or is there a better way to do this that I am missing.
Adding 3600 to $next_payday while its going through the while loop works as well, but I do not really want to do it that way. I'm sure it will mess me up in the fall when DST happens again and I lose an hour.
Thanks for any input.
Upvotes: 0
Views: 1089
Reputation: 47894
Incrementing time using 86400
or (60*60*24)
is going to warp your results whenever a DST event is encountered. Fortunately strtotime()
doesn't suffer from the effects when you add days, weeks, etc.
The DateTime construct is all fine and good, but I haven't yet needed it for any of my simple datetime processes. This case is no exception.
When I tested your code, it never entered the while loop because strtotime()
values were not quoted and so were converted into unexpected timestamps that set $next_payday
greater than $due_date
.
This code will correctly tally the number of payperiod in the date range:
//declare paychecks as counter
$paychecks = 0;
//the number of days a user has between paychecks
$frequency = 14;
// or you could use 2 and set the strtotime unit to "+$frequency weeks"
//users next payday
$next_payday = strtotime("2017-03-10"); // this date value needed quotes
//the date the next bill is due
$due_date = strtotime("2017-03-24"); // this date value needed quotes
//echo date("Y-m-d",$next_payday),"<br>",date("Y-m-d",$due_date),"<br>";
while($next_payday<=$due_date){
++$paychecks; // 2017-03-10 & 2017-03-24
$next_payday=strtotime(date("Y-m-d",$next_payday)." +$frequency days");
}
//echo "next_payday=",date("Y-m-d",$next_payday),"<br>"; // this will be beyond $due_date
echo $paychecks; // 2
p.s. Yes, the while loop could have been turned into a less readable one-liner (which I always like to seek out).
while($next_payday<=$due_date && $next_payday=strtotime(date("Y-m-d",$next_payday)." +$frequency days")){++$paychecks;}
Upvotes: 1