PHP Finding Start and End dates of week given a date

I need to find the start date (sunday) through the end date (saturday) of a given week.  For input, I have a date somewhere within the week formatted 0000-00-00 from a mysql query.  The server is running PHP 4.x.

I'm using the attached code and calling the function via date = Main::WeekDates($y,$w,"start");

My problem is that everytime I get a returned value of 1969-12-31 which I know isn't true.


function WeekDates($year, $week, $type)
        {
                $from = date("Y-m-d", strtotime("{$year}-W{$week}-1")); //should return the date of Monday???
                $to = date("Y-m-d", strtotime("{$year}-W{$week}-7")); //should return the date of Sunday???
                switch ($type)
                {
                        case "start" :
                                return $from;
                        break;
                        case "end" :
                                return $to;
                        break;
                }
        }

Open in new window

chris_thornAsked:
Who is Participating?
 
FartingUncleCommented:
UPDATE: Amended to return date in SQL format.
<?php
function WeekDates($year, $week, $type = "start") {
        $secs_in_day = 60 * 60 * 24;
        
        $date = strtotime($year . "-01-01");
        $date = $date + ($secs_in_day * 7 * $week);

        $day = strftime("%w", $date);

        if ($type == "start")
                $date = $date - ($day * $secs_in_day);
        else
                $date = $date + ((6 - $day) * $secs_in_day);

        return strftime("%Y-%m-%d", $date);
}

$date = WeekDates(2010, 38, "start");
print($date . "\n");
$date = WeekDates(2010, 38, "end");
print($date . "\n");

// Outputs:
//      2010-09-19
//      2010-09-25

Open in new window

0
 
FartingUncleCommented:

<?php
function WeekDates($year, $week, $type = "start") {
	$secs_in_day = 60 * 60 * 24;
	
	$date = strtotime($year . "-01-01");
	$date = $date + ($secs_in_day * 7 * $week);

	$day = strftime("%w", $date);

	if ($type == "start")
		return $date - ($day * $secs_in_day);
	else
		return $date + ((6 - $day) * $secs_in_day);
}

$date = WeekDates(2010, 38, "start");
print(strftime("%d/%m/%Y", $date) . "\n");
$date = WeekDates(2010, 38, "end");
print(strftime("%d/%m/%Y", $date) . "\n");

// Outputs:
// 	19/09/2010
// 	25/09/2010

Open in new window

0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

 
chris_thornAuthor Commented:
You are the man....thanks much
0
 
Ray PaseurCommented:
Here is a general solution to the Sunday part of the function.  
<?php // RAY_temp_weekdates.php
error_reporting(E_ALL);
echo "<pre>";

function SundayDates($year, $week)
{
    // GET A DATE RELATIVE TO THE BEGINNING OF THE YEAR
    $fdate = date("r", strtotime("$year-01-01 + $week WEEKS"));
    // GET THE NUMBER OF THIS DAY OF THE WEEK
    $wkday = date("w", strtotime($fdate));
    // IF SUNDAY
    if ($wkday == 0) return $fdate;
    // IF NOT SUNDAY, GET THE LAST SUNDAY
    return date('r', strtotime($fdate . " LAST SUNDAY"));
}

echo SundayDates(2010, 36);

Open in new window

0
 
Ray PaseurCommented:
You might want to leave questions like this open a little longer -- you may find there are other experts who can offer a fresh perspective on the problem.   There is no need to compute the number of seconds in a day in order to find a week number - PHP has built-in functions for this sort of thing.

Anyway, good luck with it, ~Ray
<?php // RAY_temp_weekdates.php
error_reporting(E_ALL);
echo "<pre>";

function WeekDates($year, $week, $type="start")
{
    // GET A DATE RELATIVE TO THE BEGINNING OF THE YEAR
    $fdate = date("Y-m-d", strtotime("$year-01-01 + $week WEEKS"));

    // GET THE NUMBER OF THIS DAY OF THE WEEK
    $wkday = date("w", strtotime($fdate));

    // IF SUNDAY
    if ($wkday == 0)
    {
        $sun = $fdate;
        $sat = date('Y-m-d', strtotime($fdate . " NEXT SATURDAY"));
    }
    // IF SATURDAY
    elseif ($wkday == 6)
    {
        $sat = $fdate;
        $sun = date('Y-m-d', strtotime($fdate . " LAST SUNDAY"));
    }
    // OTHER DAYS
    else
    {
        $sat = date('Y-m-d', strtotime($fdate . " NEXT SATURDAY"));
        $sun = date('Y-m-d', strtotime($fdate . " LAST SUNDAY"));
    }

    // ANSWER
    if ($type == 'start') return $sun;
    if ($type == 'end') return $sat;
    return 'ERROR IN TYPE';
}

// SOME TEST DATA
echo PHP_EOL . WeekDates(2010, 0);
echo PHP_EOL . WeekDates(2010, 1);
echo PHP_EOL . WeekDates(2010, 36);
echo PHP_EOL . WeekDates(2010, 52);
echo PHP_EOL . WeekDates(2010, 53);
echo PHP_EOL . WeekDates(2010, 54);

Open in new window

0
 
FartingUncleCommented:
> There is no need to compute the number of seconds in a day in order
> to find a week number - PHP has built-in functions for this sort of thing.

Sure, but multiplication is a hell of a lot quicker than parsing strtotime().  If this is being called on every row in a large results set then that could be a significant issue, so the fewer calls the better.
0
 
Ray PaseurCommented:
@FartingUncle:

Not sure I agree.  In my experience, the built-in PHP functions are very fast (usually a great deal faster than anything we can write in PHP to simulate the work of the core).

Would like to see how you could support that statement, especially how many calls would be needed to generate one second of difference in speed.  Usually if it's not worth a second of elapsed time, it does not get on my radar screen.

Also, I cannot envision any application that would need to call this more than once for every row of a large results set.  It is not data that would change, so a sensible design might compute the values once, and store the values thereafter.  

Best to all, ~Ray
0
 
FartingUncleCommented:
You're right that an internal PHP function will (normally*) be faster than an equivalent implementation written in PHP itself, but that's not the case when you're comparing:

   $date - ($day * $secs_in_day)

with

   strtotime($date . " LAST SUNDAY")

I have not done any profiling to confirm this or to verify how much of a difference it would make, so I'm only talking from a theoretical point of view at the moment.  However, it seems obvious to me that a subtraction followed by a multiplication is going to be significantly quicker than string concatenation followed by string parsing followed by whatever internal calculations are being performed (which I would bet are significantly more complicated than a subtraction followed by a multiplication, bearing in mind it has to convert the text representation of the date into a unix timestamp before it can do anything with it).  

Whether that is a problem or not depends on how it is being used, about which I know nothing.  I agree with your point that you would need a fair number of calls before it became a problem, but bear in mind that a script that just calls the function just once, called within a page that is viewed thousands of times per second = function being called thousands of times per second.
 
All the best,

- Mark


* For example, I read somewhere recently how a binary search algorighm written in PHP is quicker than the native array_search() function, if the array to be searched is already sorted.
0
 
Ray PaseurCommented:
Yes, I take your point.  I'm just curious at a kind of micro-curiosity level about the performance question.  Often I have seen elaborate PHP code structures that replicate the built-in functions relative to DATETIME only to overlook such details as months having a different number of days or leap years.  Those things seem to be pretty-well baked into the core.  Maybe I will test it if I have a period of ennui.  My guess is that any performance difference would pale in comparison to the differences you might find with good indexing of the data base tables.

cheers, ~Ray
0
 
FartingUncleCommented:
Agreed.  There are likely to be better performance gains to be found elsewhere, if that is an issue.
0
 
Ray PaseurCommented:
@FartingUncle:  Here's a test case.  You can install it on your server and see if you get similar results to mine.

You're right that the math algorithm beats the performance of the text-based functions by a large amount (it was consistently twice as fast).  But "large" is relative.  The measurable difference on my server showed up in the fourth decimal place.  I made several tests and found that the difference was usually about 0.0001 seconds.  A comparable number would be a disk spinning at 7,200 RPM; it makes a single revolution in 0.00014 seconds.

So I am guessing that after several thousand iterations through the functions you could find a difference of a second.

Sidebar note: While I was dicking around with this, I found that date() was a bit faster than strftime() - probably due to the locale-aware nature of strftime().  That difference appeared in the sixth decimal place.

Best to all, ~Ray

<?php // RAY_temp_time_weekdates.php
error_reporting(E_ALL);

// COMPARISON OF THE TIME IT TAKES TO RUN FUNCTIONS

function Farting_Uncle_WeekDates($year, $week, $type = "start") {
        $secs_in_day = 60 * 60 * 24;

        $date = strtotime($year . "-01-01");
        $date = $date + ($secs_in_day * 7 * $week);

        $day = strftime("%w", $date);

        if ($type == "start")
                $date = $date - ($day * $secs_in_day);
        else
                $date = $date + ((6 - $day) * $secs_in_day);

        return strftime("%Y-%m-%d", $date);
}


function Ray_Paseur_WeekDates($year, $week, $type="start")
{
    // GET A DATE RELATIVE TO THE BEGINNING OF THE YEAR
    $fdate = date("Y-m-d", strtotime("$year-01-01 + $week WEEKS"));

    // GET THE NUMBER OF THIS DAY OF THE WEEK
    $wkday = date("w", strtotime($fdate));

    // IF SUNDAY
    if ($wkday == 0)
    {
        $sun = $fdate;
        $sat = date('Y-m-d', strtotime($fdate . " NEXT SATURDAY"));
    }
    // IF SATURDAY
    elseif ($wkday == 6)
    {
        $sat = $fdate;
        $sun = date('Y-m-d', strtotime($fdate . " LAST SUNDAY"));
    }
    // OTHER DAYS
    else
    {
        $sat = date('Y-m-d', strtotime($fdate . " NEXT SATURDAY"));
        $sun = date('Y-m-d', strtotime($fdate . " LAST SUNDAY"));
    }

    // ANSWER
    if ($type == 'start') return $sun;
    if ($type == 'end') return $sat;
    return 'ERROR IN TYPE';
}


function Optimized_1_WeekDates($year, $week, $type='start')
{
    // GET A DATE RELATIVE TO THE BEGINNING OF THE YEAR
    $fdate = date("Y-m-d", strtotime("$year-01-01 + $week WEEKS"));

    // GET THE NUMBER OF THIS DAY OF THE WEEK
    $wkday = date("w", strtotime($fdate));

    // IF SUNDAY
    if ($type == 'start')
    {
        if ($wkday == 0)
        {
            return $fdate;
        }
        return date('Y-m-d', strtotime($fdate . " LAST SUNDAY"));
    }

    // IF SATURDAY
    if ($type == 'end')
    {
        if ($wkday == 6)
        {
            return $fdate;
        }
        return date('Y-m-d', strtotime($fdate . " NEXT SATURDAY"));
    }

    // IF ERROR IN TYPE
    return 'ERROR IN TYPE';
}


function Optimized_2_WeekDates($y, $w, $t='start') {

    $n = strtotime($y . "-01-01") + (604800 * $w);
    $d = date('w', $n);
    if ($t == "start") return date("Y-m-d", $n - ($d * 86400) );
    return date("Y-m-d", $n + ( (6 - $d) * 86400) ) ;
}


ob_start();
$count    = 1000;
$decimals = 6;
$type     = 'start';
echo "<pre>" . PHP_EOL;

// TEST ALGORITHM ONE
$kount = $count;
$array = array();
$fualpha = round( microtime(true),$decimals);
while ($kount)
{
    $kount--;
    $array[] = Farting_Uncle_WeekDates(2010, 36, $type);
}
$fuomega = round( microtime(true),$decimals);
$fulapse = $fuomega - $fualpha;
echo "<br />FU TIME: " . number_format($fulapse/$count,$decimals) . PHP_EOL;
var_dump($array[0]);


// TEST ALGORITHM TWO
$kount = $count;
$array = array();
$rpalpha = round( microtime(true),$decimals);
while ($kount)
{
    $kount--;
    $array[] = Ray_Paseur_WeekDates(2010, 36, $type);
}
$rpomega = round( microtime(true),$decimals);
$rplapse = $rpomega - $rpalpha;
echo "<br />RP TIME: " . number_format($rplapse/$count,$decimals) . PHP_EOL;
var_dump($array[0]);


// TEST ALGORITHM THREE
$kount = $count;
$array = array();
$o1alpha = round( microtime(true),6);
while ($kount)
{
    $kount--;
    $array[] = Optimized_1_WeekDates(2010, 36, $type);
}
$o1omega = round( microtime(true),$decimals);
$o1lapse = $o1omega - $o1alpha;
echo "<br />O1 TIME: " . number_format($o1lapse/$count,$decimals) . PHP_EOL;
var_dump($array[0]);


// TEST ALGORITHM FOUR
$kount = $count;
$array = array();
$o2alpha = round( microtime(true),$decimals);
while ($kount)
{
    $kount--;
    $array[] = Optimized_2_WeekDates(2010, 36, $type);
}
$o2omega = round( microtime(true),$decimals);
$o2lapse = $o2omega - $o2alpha;
echo "<br />O2 TIME: " . number_format($o2lapse/$count,$decimals) . PHP_EOL;
var_dump($array[0]);

Open in new window

0
 
FartingUncleCommented:
Interesting - good to know.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.