jwwceo Posted June 19, 2009 Share Posted June 19, 2009 I am writing an application where the admin can assign an event, and then can also say how often the event is repeated, for example, annually, monthly, weekly, every 3 weeks, every 2 weeks, daily, etc. They can also assign how many days in advance of the event to trigger a reminder for the event. I am then using a calendar display I wrote to display events on the calendar. The calendar is displayed one month at a time, and loops through all the days in that month. For every day in the month, say "01-01-08", it then loops through all the events and looks for matching dates and displays an event which occurs on that particular day. This part is working fine. The part that makes me scratch my head is the repeating events. If an even is "01-01-08" and set to repeat every 2 weeks in perpetuity, then there is this huge list of future dates which fit that criteria. How would I take a date in the future, say "12-15-2015" and see if it falls on one of those days. So I am thinking I need to write a function which will take 3 parameters: 1. The original date. 2. The repeating frequency 3. The current date which will compare if the current date applies. Seems pretty hairy. Then I will have to modify it, and make another function that takes into consideration how many days in advance to set the notice. So that funciton would compare the current date to the "notification date", and see if that applies, and if so...set the notification. I hope this makes sense. I'd be happy to clarify if it does not. I also think (maybe) I can solve this as long as the dates are not too far in the future. I could limit it to like 10 years and check the re-occurring dates, and as a long as they are less than the 10 year limit, the loop would continue finding future dates, add them to an array of future repeating dates, and then check the current date against that. For example, if an event is occuring every 2 weeks, I could use the strtotime function a bunch of times. But I am curious about writing the function which would work for any future date. I would love thoughts on this. james Quote Link to comment Share on other sites More sharing options...
thebadbad Posted June 19, 2009 Share Posted June 19, 2009 Here's my go on your first function. It calculates the difference in days between the original date and the future date, and then calculates the remainder of the difference in days divided by the repeating frequency in days (modulus). If it's 0, the original event occurs on the future date. <?php /* Checks if the original event on $orig_date with repeating frequency $freq occurs on $future_date * * @param string $orig_date (date in any format recognized by strtotime()) * @param int $freq (repeating frequency in days) * @param string $future_date (date in any format recognized by strtotime()) * @return bool */ function freq_date_match($orig_date, $freq, $future_date) { $orig_stamp = strtotime($orig_date); $future_stamp = strtotime($future_date); $diff_secs = $future_stamp - $orig_stamp; $diff_days = $diff_secs / 60 / 60 / 24; if (($diff_days % $freq) == 0) { return true; } else { return false; } } //test if (freq_date_match('2009-06-20', 5, '2009-06-30')) { echo 'Match!'; } ?> Should be much more efficient than comparing the future date to every repeating date, based off the original date. Quote Link to comment Share on other sites More sharing options...
jwwceo Posted June 19, 2009 Author Share Posted June 19, 2009 nice...very elegant..the code I was working on was way more complex... I will try this and see if it works for my app. Thanks a bunch!!! Quote Link to comment Share on other sites More sharing options...
jwwceo Posted June 19, 2009 Author Share Posted June 19, 2009 ah..here's the problem... not all the frequencies are in days... an event that repeats monthly will sometimes be 30 days later, and sometimes 31..and rarely 28.. an annual event will usually be 365 days later..but not always..because of leap years and such... thats why the strtotime seemed useful...in a that it can accept normal language like +1 month without knowing how many days exactly it might be. James Quote Link to comment Share on other sites More sharing options...
thebadbad Posted June 20, 2009 Share Posted June 20, 2009 To check if a notification should be added, we can simply add an optional offset parameter to the function. Updated function: <?php /* Checks if the original event on $orig_date with repeating frequency $freq occurs on $future_date * * @param string $orig_date (date in any format recognized by strtotime()) * @param int $freq (repeating frequency in days) * @param string $future_date (date in any format recognized by strtotime()) * @param int $offset (negative offset in days) * @return bool */ function freq_date_match($orig_date, $freq, $future_date, $offset = 0) { $orig_stamp = strtotime($orig_date); $future_stamp = strtotime($future_date); $diff_secs = $future_stamp - $orig_stamp; $diff_days = ($diff_secs / 60 / 60 / 24) + $offset; if (($diff_days % $freq) == 0) { return true; } else { return false; } } //test //if 2009-06-23 occurs 2 days before one of the original event's repeats (every 5th day, beginning 2009-06-20) if (freq_date_match('2009-06-20', 5, '2009-06-23', 2)) { echo 'Match!'; } ?> Just to be clear: Note that you can use this function for both your tasks. Just specify the number of days the notifications should appear in advance as the fourth parameter when checking for notifications. Edit: Just realized that problem you're mentioning. I'll see if I can think up a solution. Quote Link to comment Share on other sites More sharing options...
thebadbad Posted June 20, 2009 Share Posted June 20, 2009 Added a frequency unit ('days', 'weeks', 'months' or 'years'): <?php /* Checks if the original event on $orig_date with repeating frequency $freq occurs on $future_date * * @param string $orig_date (date in any format recognized by strtotime()) * @param int $freq (repeating frequency in $freq_unit) * @param string $freq_unit ('days', 'weeks', 'months' or 'years') * @param string $future_date (date in any format recognized by strtotime()) * @param int $offset (negative offset in days) * @return bool */ function freq_date_match($orig_date, $freq, $freq_unit, $future_date, $offset = 0) { if (!in_array($freq_unit, array('days', 'weeks', 'months', 'years'))) { die('Error: Invalid third parameter passed to function freq_date_match().'); } $orig_stamp = strtotime($orig_date); $future_stamp = strtotime($future_date); switch ($freq_unit) { //if unit is weeks, multiply $freq with 7 and move on to calculation with days case 'weeks': $freq *= 7; case 'days': $diff_secs = $future_stamp - $orig_stamp; $diff_days = ($diff_secs / 60 / 60 / 24) + $offset; if (($diff_days % $freq) == 0) { return true; } else { return false; } break; //if unit is years, multiply $freq with 12 and move on to calculation with months case 'years': $freq *= 12; case 'months': while ($orig_stamp <= $future_stamp) { if ($orig_stamp == $future_stamp) { return true; } $orig_stamp = strtotime("+ $freq months - $offset days", $orig_stamp); } return false; break; } } //test //if 2009-08-20 occurs on one of the original event's repeats (every 2nd month, beginning 2009-06-20) if (freq_date_match('2009-06-20', 2, 'months', '2009-08-20')) { echo 'Match!'; } ?> I'm using a while loop to check the repeating dates when months or years are given as frequency, returning true if the timestamps match or false if the future date is reached without a match. Now I don't know if using this function for each check is more efficient than creating an array of every repeating date of each event to check against. But I hope and think it is Just remember that the current upper limit of a Unix timestamp is 19 Jan 2038 (corresponding to the maximum value for a 32-bit signed integer). Meaning you can't check future dates beyond that point. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.