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.

\$\endgroup\$
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;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.