perkiset

NBs and I went back and forth on ways to handle things like "Get me the second Friday in March 2007" or "Get me the last Monday in February 2006." We have two different ways of going at it and I thought the results were pretty good.

Below is my final iteration, NBs, please post yours as well.

Here is the spam for the engines:
date functions in

php

 
complex date functions
advanced date math
date calculation
First Second Third Fourth Fifth Last
Monday Tuesday Wednesday Thursday Friday Saturday Sunday
January February March April May June July August September October November December



<?

php

 

// This function returns a date-type value based on the parameters passed
// Days are ISO standard: 1==Monday, 7==Sunday.
// specialDate(2, 1, 6, 2007) would return the second Monday of June 2007
// specialDate(-1, 5, 1, 2006) would return the LAST Friday of January 2006.

function specialDate($offset, $dayofweek, $month, $year)
{
if (!$offset)
throw new Exception('specialDate: Parameter 0 (offset) must not be zero');
if (($dayofweek < 1) or ($dayofweek > 7))
throw new Exception('specialDate: Parameter 1 (Day Of Week) must be 1..7');
if (($month < 1) or ($month > 12))
throw new Exception('specialDate: Parameter 2 (Month) must be 1..12');

// Invert the offset such that if it's >=4 it becomes -1, or <=-4 it becomes 1...
$offset = (abs($offset) >= 4) ? (($offset / abs($offset)) * -1) : $offset;

if ($offset > 0)
{
// Make a base time the first of the target month
$time = mktime(0, 0, 0, $month, 1, $year);
$move = 86400;
$weeks = --$offset * 604800;
} else {
// Make a base time the last of the target month
$time = mktime(0, 0, 0, $month + 1, 1, $year) - 86400;
$move = -86400;
$weeks = ++$offset * 604800;
}

// Now find the first matching DayOfWeek...
while (date('N', $time) <> $dayofweek) { $time += $move; }

// return the time, offset by weeks...
return $time + $weeks;
}
?>

nutballs

The only significant difference other than methodology is that my function recursively calls itself to determine the first occurrence in the future of the date requested, if $forcefuture is true. This is a specific need that I have for my project however, you can eliminate it by chopping out the $forcefuture parameter and the stuff noted by the comments below.


<?

php

 
function specialDate($offset, $dayofweek, $month, $year, $forcefuture=false)
{
//error handling. this is generic do what you want.
if ((abs($offset) > 5) or ($offset == 0)) { return false; }
if (($dayofweek < 1) or ($dayofweek > 7)) { return false; }
if (($month < 1) or ($month > 12)) { return false; }

//make a base time assume the first of the month
$time = mktime(0,0,0,$month,1,$year);

$move = 1; //positive 1. just a single unit variable for plus or minus calcs

//we want something from the end of the month. so...
//increase 1 month and then decrease 1 day. puts you on last day of month
if ($offset < 0)
{
$time = DateAdd('m', 1, $time);
$time = DateAdd('d', -1, $time);
$move = -1; //going backward from end of month, so move is changed to negative
}

// Now find the first matching DayOFWeek...
while (date('N', $time) <> $dayofweek)
{
$time = DateAdd('d',$move,$time); //forward or back in time depending on neg/pos of $move
}

//determine how many weeks to add, $offset -1
//but since offset can be negative, we need to do funky math to reduce the offset value towards zero.
$time=DateAdd('w',($offset/abs($offset))*(abs($offset)-1),$time);

// Make sure that the offset or $weeks has not pushed me out of the target month...
//roll back or forward a week to get back into month. invert $move
if (date('m', $time) <> $month)
{
$time = DateAdd('w',-$move,$time);
}

//if we are forcing a future date, we recursively call this function with 1 year greater
        //if you dont care about enforcing future dates, you can chop out this part.
if (($forcefuture) and ($time < time()))
{
$time = specialDate($offset, $dayofweek, $month, $year+1, $forcefuture);
}

        //uh yea, return the timestamp of the specialdate
return $time;
}


//a Date shifting function that deals with leapyear and crazyness like that
function DateAdd($interval, $number, $time)
{
switch ($interval)
{
case 'y':
$timestamp = strtotime($number.' years', $time);
break;
case 'm':
$timestamp = strtotime($number.' months', $time);
break;
case 'd':
$timestamp = strtotime($number.' days', $time);
break;
case 'w':
$timestamp = strtotime($number.' weeks', $time);
break;
case 'h':
$timestamp = strtotime($number.' hours', $time);
break;
case 'n':
$timestamp = strtotime($number.' minutes', $time);
break;
case 's':
$timestamp = strtotime($number.' seconds', $time);
break;
}
return $timestamp;
}

?>


Perkiset's Place Home   Politics @ Perkiset's