Author |
Message |
mrmortimer
New Member


Joined: Jan 22, 2008
Posts: 13
|
Posted:
Thu Mar 06, 2008 4:17 am |
|
I've posted this same question to several PHP related sites almost a week ago, with absolutely no response. You folks seem to be my "last resort", so to speak.
I've built a "web app" in PHP to handle data and business operations for the cab company I work for, and a part of the application acts as a sort of "alarm clock", displaying pre-arranged pick-ups and wake up calls. Here's the "full story":
The other day, our server was upgraded to a faster computer, and the entire application's infrastructure were upgraded, as well (apache server 2.0 to 2.2.3, php 5.0 to 5.2.5, and mySQL 4.3 to 5.0.25). I've gotten all the usual headaches dealt with (changing query syntax, fixing the "old password" hassle, etc.), except for one, and I'm not sure what to do about it. I'm missing something simple, I just know it. The trouble lies in the following section of code:
Code:
list($h, $m) = split(":", $time);
// hh:mm syntax string, retrieved from the db
$timeOffset = "+$h hours $m minutes";
// $timeOffset is the fine offset (from midnight) to add to the event's current timestamp
$recurring = ($recurring >= 128) ? $recurring - 128 : $recurring;
// $recurring is an 8 bit flag field, denoting wether to repeat the event
// on a later day/days, or if it's a single-use event.
// If $recurring is 128, that denotes a monthly event, which is
// handled later on (and works fine)
$rBin = str_pad(decBin($recurring),7,"0",STR_PAD_LEFT);
//$rBin converts $recurring to a string, representing a 7 bit binary number
$w = date("w", $timestamp);
$c1 = substr($rBin,0,$w);
$c2 = substr($rBin,$w);
$c3 = "$c2$c1";
// the above block determines which day of the week is current, and
// reconstructs the string, starting with the current day
$c = $x = 0;
while ($c == 0) {
$x++;
$c = intval(substr($c3,$x,1));
if ($x >= 7) break;
}
// the above loop counts the number of days till the next event is to occur
$next = "+$x day";
$next .= ($x == 1) ? "" : "s";// if more than one day, make it plural
// $next is the gross offset, in days, to add to the event's current timestamp
break;// Part of an earlier switch statement (not shown)
}
$oldDate = $date;// The event's last stored date
$oldTS = strtotime($date);// The current unix timestamp for the event (midnight)
$oldTS = strtotime($next, $oldTS);// Add the gross offset
$newTimestamp = strtotime($timeOffset, $oldTS);// Add the fine offset
|
Fact Sheet:
$recurring binary bit values (shown in decimal):
Monthly = 128
Sunday = 64
Monday = 32
Tuesday = 16
Wednesday = 8
Thursday = 4
Friday = 2
Saturday = 1
None = 0
Now here's where it gets interesting. The generated timestamp is accurate about half of the time. But when it's off, it's off by as much as several hours, in either direction (e.g. gets set for 09:15, instead of 05:30, or for 23:30 on the previous day, rather than 06:00 {military time is used for ease of coding}). I have no clue at all what's triggering the inaccuracies.
I'm completely baffled by this behavior, and I'm looking for a more reliable way to handle this. Any suggestions would be humbly and gratefully accepted. |
Last edited by mrmortimer on Fri Mar 07, 2008 7:41 am; edited 1 time in total |
|
|
 |
Gremmie
Former Moderator in Good Standing

Joined: Apr 06, 2006
Posts: 2415
Location: Iowa, USA
|
Posted:
Thu Mar 06, 2008 8:18 am |
|
Sorry, thats an awful lot of code to try and digest. My first thought is "why do all that yourself?". There is this amazing function in php called strtotime() which I use all over the place in GCalendar. It is built on top of a GNU C library which does the same thing. Anyway, it can parse just about any "natural language" string into a time for you, and it handles all the corner cases as well. Maybe you could leverage that in your code.
http://us.php.net/manual/en/function.strtotime.php
What it can parse:
http://www.gnu.org/software/tar/manual/html_node/tar_113.html
You can say things like
$x = some timestamp value
strtotime('+4 hours', $x);
strtotime('-1 month, $x);
strtotime('3 years ago', $x);
strtotime('third monday', $x);
strtotime('next tuesday', $x);
I'm only scratching the surface, it's an amazingly useful function. |
_________________ Only registered users can see links on this board! Get registered or login! - An Event Calendar for PHP-Nuke
Only registered users can see links on this board! Get registered or login! - A Google Maps Nuke Module |
|
|
 |
mrmortimer

|
Posted:
Thu Mar 06, 2008 5:47 pm |
|
Well, after working on trying to state the problem more clearly, I decided to rewrite that section to make it more understandable, and guess what? It now works!
The new and improved code (more of it, actually) follows:
Code:
function fillIn($out = "") {
$id = $_POST['id'];
$sql = "select * from `time calls` where `id` = $id";
$out .= "<!-- SQL1 = $sql -->\n";
$row = getDB_row($sql, "fillIn");
if ($row != NULL) {
foreach ($row as $key => $value) {
$$key = $value;
}
$tcn = ($type == "Time Call") ? "tc$time" : "";
$tcNotes = ($notes != "") ? "$tcn - $notes" : $tcn;
$addnotes = ($type == "Time Call") ? "top.frmNew.dbMain[mn].value = '$tcNotes';" : "";
$out .= <<<endScript
<script type="text/javascript">
addTCvals("$address", "$addnotes")
</script>
endScript;
/*
Values for recurring time calls:
Monthly = 128
Sunday = 64
Monday = 32
Tuesday = 16
Wednesday = 8
thursday = 4
Friday = 2
Saturday = 1
*/
$fineOffset = "+0 minutes";
if ($recurring != 0) {
switch ($recurring) {
case 128:
$next = "+1 month";
break;
default:
list($h, $m) = split(":", $time);
$fineOffset = "+$h hours $m minutes";
$recurring = ($recurring >= 128) ? $recurring - 128 : $recurring;
$rBin = str_pad(decBin($recurring),7,"0",STR_PAD_LEFT);
$w = date("w", $timestamp);
$c1 = substr($rBin,0,$w);
$c2 = substr($rBin,$w);
$c3 = "$c2$c1";
$c = $x = 0;
while ($c == 0) {
$x++;
$c = intval(substr($c3,$x,1));
if ($x >= 7) break;
}
$next = ($x == 1) ? "+$x day" : "+$x days";
}
$typeOffset = ($type == "Time Call") ? 15 : 1;
$typeOffset += $sendEarly;
$typeOffsetString = "-$typeOffset minutes";
$oldDate = "$date 00:00";
$timestamp = strtotime($date);
$oldTimestamp = strtotime($oldDate);
$oldTimestampDate = date("m/d/Y H:i", $oldTimestamp);
$grossOffsetTimestamp = strtotime($next, $oldTimestamp);
$grossOffsetDate = date("m/d/Y H:i", $grossOffsetTimestamp);
$fineOffsetTimestamp = strtotime($fineOffset, $grossOffsetTimestamp);
$fineOffsetDate = date("m/d/Y H:i", $fineOffsetTimestamp);
$finalTimestamp = strtotime($typeOffsetString, $fineOffsetTimestamp);
$finalDate = date("m/d/Y", $finalTimestamp);
$finalTime = date("H:i", $finalTimestamp);
$out .= "<!-- newTimestamp = $finalTimestamp -->\n";
$sql = "update `time calls` set `timestamp` = $finalTimestamp, `testTime` = '$testTime', `date` = '$finalDate', `time` = '$time' where `ID` = $ID";
}
else {
$sql = "update `time calls` set `sent` = 1 where `ID` = $ID";
}
$out .= "<!-- SQL2 = $sql -->\n";
$tmp = updateDB($sql, "fillIn");
}
return $out;
}
|
I'm not 100% sure why recoding it with different variable names did the trick, unless I used the wrong variable in the earlier version, and just plain missed it. But at least it works, and that's what matters.
Thanks for helping, Gremmie. Causing me to sharpen my code is what turned the trick. |
|
|
|
 |
|