Solved

PHP Finding Start and End dates of week given a date

Posted on 2010-09-08
13
988 Views
Last Modified: 2012-05-10
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

0
Comment
Question by:chris_thorn
  • 6
  • 6
13 Comments
 
LVL 1

Expert Comment

by:FartingUncle
ID: 33629349

<?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
 
LVL 1

Accepted Solution

by:
FartingUncle earned 500 total points
ID: 33629392
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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33629825
0
 

Author Closing Comment

by:chris_thorn
ID: 33629871
You are the man....thanks much
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33629933
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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33630054
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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 1

Expert Comment

by:FartingUncle
ID: 33631537
> 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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33632077
@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
 
LVL 1

Expert Comment

by:FartingUncle
ID: 33632459
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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33633090
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
 
LVL 1

Expert Comment

by:FartingUncle
ID: 33635050
Agreed.  There are likely to be better performance gains to be found elsewhere, if that is an issue.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 33636960
@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
 
LVL 1

Expert Comment

by:FartingUncle
ID: 33645241
Interesting - good to know.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Read about why website design really matters in today's demanding market.
This article discusses four methods for overlaying images in a container on a web page
This tutorial walks through the best practices in adding a local business to Google Maps including how to properly search for duplicates, marker placement, and inputing business details. Login to your Google Account, then search for "Google Mapmaker…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now