2
\$\begingroup\$

I started actually learning a little programming last year, as opposed to just hacking away at libraries and found fragments.

For a WordPress plugin I needed to navigate through weeks, which I thought would be pretty easy. Well it should have been, but my method of using the week and the year returned by php based on timestamp got interesting, when navigating back and forth across years around this time of year.

What I ended up with was an obvious mess, but seemed to work... until today.

For your amusement I thought I would share the original code, as well as the refactored code, out of which I created a little WordPress plugin in case it's useful for anyone else developing a WP plugin that requires date navigation.

The original mess:

function mz_mbo_schedule_nav($mz_get_variables)
{
 $sched_nav = '';
 $mz_schedule_page = get_permalink();
 //sanitize input
 //set week number based on php date or passed parameter from $_GET
 $mz_weeknumber = empty($mz_get_variables['mz_week']) ? date_i18n("W", strtotime(date_i18n('Y-m-d'))) : mz_validate_weeknum($mz_get_variables['mz_week']);
 //Navigate through the weeks
 $mz_nav_weeks_text_prev = __('Previous Week');
 $mz_nav_weeks_text_current = __('Current Week');
 $mz_nav_weeks_text_following = __('Following Week');
 $mz_current_year = strftime('%G', strtotime(date_i18n('Y-m-d'))); 
 $num_weeks_in_year = mz_weeknumber($mz_current_year, 12, 31);
 if (($mz_weeknumber < $num_weeks_in_year) && empty($mz_get_variables['mz_next_yr']))
 {
 if ($mz_weeknumber == 01)
 {//if we are in first week of year
 $mz_num_weeks_back = add_query_arg(array('mz_week' => ($num_weeks_in_year - 1)));
 }else{
 $mz_num_weeks_back = add_query_arg(array('mz_week' => ($mz_weeknumber - 1)));
 }
 $mz_num_weeks_forward = add_query_arg(array('mz_week' => ($mz_weeknumber + 1)));
 $sched_nav .= ' <a href='.$mz_num_weeks_back.'>'.$mz_nav_weeks_text_prev.'</a>';
 $sched_nav .= ' - <a href='.$mz_schedule_page.'>'.$mz_nav_weeks_text_current.'</a> - ';
 $sched_nav .= '<a href='.$mz_num_weeks_forward.'>'.$mz_nav_weeks_text_following.'</a>';
 $mz_start_end_date = mz_getStartandEndDate($mz_weeknumber,$mz_current_year);
 }
 else
 { //BOF following year
 $mz_next_year = isset($mz_get_variables['mz_next_yr']) ? mz_validate_year($mz_get_variables['mz_next_yr']) : "1";
 $mz_weeknumber = ($mz_weeknumber > 40) ? $mz_weeknumber - ($num_weeks_in_year - 1) : $mz_weeknumber;
 $from_the_future_backwards = ($mz_weeknumber == 2) ? $num_weeks_in_year : ($mz_weeknumber - 1);
 $mz_num_weeks_forward = add_query_arg(array('mz_week' => ($mz_weeknumber + 1), 'mz_next_yr' => ($mz_current_year + 1)));
 if ($mz_weeknumber == 01)
 {//if we are in first week of year
 $mz_num_weeks_back = add_query_arg(array('mz_week' => ($num_weeks_in_year - 1)));
 $sched_nav .= ' <a href='.$mz_num_weeks_back.'>'.$mz_nav_weeks_text_prev.'</a>';
 }
 else
 {
$mz_num_weeks_back = add_query_arg(array('mz_week' => ($mz_weeknumber - 1), 'mz_next_yr' => ($mz_current_year + 1)));
 $sched_nav .= ' <a href='.$mz_num_weeks_back.'>'.$mz_nav_weeks_text_prev.'</a>';
 }
 $sched_nav .= ' - <a href='.$mz_schedule_page.'>'.$mz_nav_weeks_text_current.'</a> - ';
 $sched_nav .= '<a href='.$mz_num_weeks_forward.'>'.$mz_nav_weeks_text_following.'</a> ';
 $mz_start_end_date = mz_getStartandEndDate($mz_weeknumber,($mz_current_year +1));
 }//EOF Following Year
 $mz_timeframe = array('StartDateTime'=>$mz_start_end_date[0], 'EndDateTime'=>$mz_start_end_date[1], 'SchedNav'=>$sched_nav);
 return $mz_timeframe;
}

I didn't bother to include the auxiliary functions, which are mostly unnecessary now.

Here's the refactored code, just sending date back and forth:

function mz_mbo_schedule_nav($mz_get_variables)
{
 $sched_nav = '';
 $mz_schedule_page = get_permalink();
 //sanitize input
 //set week number based on php date or passed parameter from $_GET
 $mz_date = empty($mz_get_variables['mz_date']) ? date_i18n('Y-m-d') : mz_validate_date($mz_get_variables['mz_date']);
 //Navigate through the weeks
 $mz_start_end_date = mz_getNavDates($mz_date);
 $mz_nav_weeks_text_prev = __('Previous Week');
 $mz_nav_weeks_text_current = __('Current Week');
 $mz_nav_weeks_text_following = __('Following Week');
 $sched_nav .= ' <a href='.add_query_arg(array('mz_date' => ($mz_start_end_date[3]))).'>'.$mz_nav_weeks_text_prev.'</a>';
 $sched_nav .= ' - <a href='.$mz_schedule_page.'>'.$mz_nav_weeks_text_current.'</a> - ';
 $sched_nav .= '<a href='.add_query_arg(array('mz_date' => ($mz_start_end_date[2]))).'>'.$mz_nav_weeks_text_following.'</a>';
 $mz_timeframe = array('StartDateTime'=>$mz_start_end_date[0], 'EndDateTime'=>$mz_start_end_date[1], 'SchedNav'=>$sched_nav);
 return $mz_timeframe;
}

And the auxiliary functions:

function mz_getNavDates($date) {
 /*Gets a YYYY-mm-dd date and returns an array of four dates:
 start of requested week
 end of requested week 
 following week start date
 previous week start date
 adapted from http://stackoverflow.com/questions/186431/calculating-days-of-week-given-a-week-number
 */
 list($year, $month, $day) = explode("-", $date);
 // Get the weekday of the given date
 $wkday = date('l',mktime('0','0','0', $month, $day, $year));
 switch($wkday) {
 case 'Monday': $numDaysToMon = 7; break;
 case 'Tuesday': $numDaysToMon = 1; break;
 case 'Wednesday': $numDaysToMon = 2; break;
 case 'Thursday': $numDaysToMon = 3; break;
 case 'Friday': $numDaysToMon = 4; break;
 case 'Saturday': $numDaysToMon = 5; break;
 case 'Sunday': $numDaysToMon = 6; break; 
 }
 // Timestamp of the monday for that week
 $monday = mktime('0','0','0', $month, $day, $year);
 $seconds_in_a_day = 86400;
 $return[0] = date('Y-m-d',$monday);// requested week
 $return[1] = date('Y-m-d',$monday+($seconds_in_a_day*$numDaysToMon));// end of requested week
 $return[2] = date('Y-m-d',$monday+($seconds_in_a_day*($numDaysToMon))); // following week
 $return[3] = date('Y-m-d',$monday+($seconds_in_a_day*($numDaysToMon - ($numDaysToMon+7)))); // previous week
 return $return;
}
function mz_validate_date( $string ) {
 if (preg_match('/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/',$string))
 {
 return $string;
 }
 else
 {
 return "mz_validate_weeknum error";
 }
}

Of course input on possible improvements on the new code are welcome.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Dec 30, 2014 at 1:30
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The above navigation wasn't quite right and needed some correction:

function mz_getNavDates($date) {
 /*Gets a YYYY-mm-dd date and returns an array of four dates:
 start of requested week
 end of requested week 
 following week start date
 previous week start date
 adapted from http://stackoverflow.com/questions/186431/calculating-days-of-week-given-a-week-number
 */
 list($year, $month, $day) = explode("-", $date);
 // Get the weekday of the given date
 $wkday = date('l',mktime('0','0','0', $month, $day, $year));
 switch($wkday) {
 case 'Monday': $numDaysFromMon = 0; break;
 case 'Tuesday': $numDaysFromMon = 1; break;
 case 'Wednesday': $numDaysFromMon = 2; break;
 case 'Thursday': $numDaysFromMon = 3; break;
 case 'Friday': $numDaysFromMon = 4; break;
 case 'Saturday': $numDaysFromMon = 5; break;
 case 'Sunday': $numDaysFromMon = 6; break; 
 }
 // Timestamp of the monday for that week
 $seconds_in_a_day = 86400;
 $monday = mktime('0','0','0', $month, $day-$numDaysFromMon, $year);
 $today = mktime('0','0','0', $month, $day, $year);
 $weeksEnd = $today+($seconds_in_a_day*(7 - $numDaysFromMon));
 $previousWeek = $monday+($seconds_in_a_day*($numDaysFromMon - ($numDaysFromMon+7)));
 $return[0] = date('Y-m-d',$today);
 $return[1] = date('Y-m-d',$weeksEnd-1);
 $return[2] = date('Y-m-d',$weeksEnd+1); 
 $return[3] = date('Y-m-d',$previousWeek); 
 return $return;
}
answered Dec 30, 2014 at 19:15
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.