5

I want to get the date of the closest Monday in the future (i.e. not in the past).

So if today is Tuesday (Dec 1, 2009) I want to get the date of Monday (Dec 7, 2009).

How can I do this with Zend_Date?

Solution:

Let's say today is Tuesday and we wanted to get the upcoming Monday. Monday is 6 days into the future. So, we would add 6 days to get monday's date.

//like so:
$tuesday = Zend_Date::now();
$nextMonday = $tuesday->addDay(6);

To do this dynamically, we will need to determine which day of the week it is today:

$today = Zend_Date::now();
$dayNumber = $today->get(Zend_Date::WEEKDAY_DIGIT);
//dayNumber will now be equal to the numeric day of the week (0-6)
//example:
$weekdays = array(
    0 => 'sunday',
    1 => 'monday',
    2 => 'tuesday' //etc...
);

To determine how many days we need to add to get the desired future day, we do the following:

$daysToAdd = ( $dayWanted - $todayDayNumber + 7 );
#      $dayWanted = monday(1)
# $todayDayNumber = tuesday(2)
#               7 = number of days in a week (we don't want a negative number)
#       1 - 2 + 7 = 6 days into the future
$nextMonday = $today->addDay($daysToAdd);

Let's say the day we want is wednesday (tomorrow), one day into the future. Our previous solution won't work:

$daysToAdd = ( $dayWanted - $todayDayNumber + 7 );
#      $dayWanted = wednesday(3)
# $todayDayNumber = tuesday(2)
#               7 = number of days in a week
#       3 - 2 + 7 = 8 days into the future (not 1)

We can solve this problem by adding the modulus operator (percent sign) to our formula to get the remainder of a division operation.

$daysToAdd = ( $dayWanted - $todayDayNumber + 7 ) % 7;
# (3 - 2 + 7) % 7
# $daysToAdd == 1 (remainder of 8 divided by 7)
$tomorrow = $today->addDay($daysToAdd);

Now our formula will work as expected...with the exception of one thing. If today is tuesday, and I want to get next tuesday, our formula will return today instead of a week from today:

$daysToAdd = ( $dayWanted - $todayDayNumber + 7 ) % 7;
# (2 - 2 + 7) % 7 == 0
# 7 goes into 7 evenly with no remainder

We will have to add a check to make sure it is not equal to zero.

if ($daysToAdd == 0) {
    //give me the date a week from today, not today's date
    $daysToAdd = 7;
}

Final Solution:

public function outputDate()
{
    $monday = $this->getDateOfNext('monday');
    echo 'today: ' . Zend_Date::now()->toString(Zend_Date::RFC_850) . "<br>";
    echo "monday: " . $monday->toString(Zend_Date::RFC_850);
}

private function getDateOfNext($dayWanted)
{
    $weekdays = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
    if (!in_array($dayWanted, $weekdays)) {
        throw new Exception("'$dayWanted' not found in array of possible weekdays");
    }
    $weekdays = array_flip($weekdays);
    $date = Zend_Date::now();
    $today = $date->get(Zend_Date::WEEKDAY_DIGIT);
    $daysToAdd = ( $weekdays[$dayWanted] - $today + 7 ) % 7;
    if ($daysToAdd == 0) {
        //give me the date a week from today, not today's date
        $daysToAdd = 7;
    }
    $date->addDay($daysToAdd);
    return $date;
}

1 Answer 1

7

Here's the logic, laid out:

$days_per_week = 7;
$weekdays = array_flip(array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'));

$day_wanted = 'mon';
$days_forward =
  ( $weekdays[$day_wanted] - $date->get(Zend_Date::WEEKDAY_DIGIT) + $days_per_week )
  % $days_per_week;

$date->addDay($days_forward);

That works nicely for any $day_wanted.

3
  • what does the ( ) % $days_per_week; do? Specifically the percent sign
    – Andrew
    Dec 19, 2009 at 20:17
  • also...what if today is tuesday, and you want to get the next tuesday? that should be 7 days forward, instead of 0. How can this be achieved?
    – Andrew
    Dec 19, 2009 at 20:22
  • The % (mod function) keeps $days_forward between 0 and 6 inclusive. If you want to jump ahead 7 days, then I'd do it after the main calculation this way: if ($days_forward == 0) $days_forward = $days_per_week. Dec 19, 2009 at 22:13

Your Answer

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

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