30

Given a week number, e.g. date -u +%W, how do you calculate the days in that week starting from Monday?

Example rfc-3339 output for week 40:

2008-10-06
2008-10-07
2008-10-08
2008-10-09
2008-10-10
2008-10-11
2008-10-12
Joe Doyle
  • 6,363
  • 3
  • 42
  • 45
hendry
  • 9,725
  • 18
  • 81
  • 139

14 Answers14

64

PHP

$week_number = 40;
$year = 2008;
for($day=1; $day<=7; $day++)
{
    echo date('m/d/Y', strtotime($year."W".$week_number.$day))."\n";
}


Below post was because I was an idiot who didn't read the question properly, but will get the dates in a week starting from Monday, given the date, not the week number..

In PHP, adapted from this post on the PHP date manual page:

function week_from_monday($date) {
    // Assuming $date is in format DD-MM-YYYY
    list($day, $month, $year) = explode("-", $_REQUEST["date"]);

    // Get the weekday of the given date
    $wkday = date('l',mktime('0','0','0', $month, $day, $year));

    switch($wkday) {
        case 'Monday': $numDaysToMon = 0; 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-$numDaysToMon, $year);

    $seconds_in_a_day = 86400;

    // Get date for 7 days from Monday (inclusive)
    for($i=0; $i<7; $i++)
    {
        $dates[$i] = date('Y-m-d',$monday+($seconds_in_a_day*$i));
    }

    return $dates;
}

Output from week_from_monday('07-10-2008') gives:

Array
(
    [0] => 2008-10-06
    [1] => 2008-10-07
    [2] => 2008-10-08
    [3] => 2008-10-09
    [4] => 2008-10-10
    [5] => 2008-10-11
    [6] => 2008-10-12
)
ConroyP
  • 40,958
  • 16
  • 80
  • 86
  • That input is not as specified. Input would be, for example, "41". – Bobby Jack Oct 09 '08 at 09:13
  • Thanks, bad case of Monday morning brain here, didn't read it properly. Answer updated with much shorter code snippet! – ConroyP Oct 09 '08 at 09:23
  • Stupid typo, not having a good morning so far! Fixed now, thanks for the spot. – ConroyP Oct 09 '08 at 10:10
  • I prefer it like: echo date('Y-m-d', strtotime(date("Y")."W".date("W").$day))."\n"; Anyway, thanks *very much* for your answer. – hendry Oct 09 '08 at 10:35
  • eeek, just noticed a difference between: `php -r "echo date("W");"` and `date -u +%W` 41 != 40 – hendry Oct 09 '08 at 11:08
  • What an amazing coincidence: i'm reading this 3 years later on the same week (40), hahaha – Jorge Guberte Oct 04 '11 at 19:32
  • I get only dates from 1999 when running your example – Jonathan Clark Feb 16 '12 at 08:45
  • This is top search result, so I just want to leave a warning. If you use posted snipped (the one using `strtotime($year."W".$week_number.$day))`) you will get unexpected results at the end of the year. – arnaslu Jun 14 '12 at 13:58
  • As previously commented there are some issues with this code. I have posted more reliable code [in my answer](http://stackoverflow.com/a/17065451/212940) – vascowhite Jun 12 '13 at 22:48
  • Maybe `DateTime` is better? > https://stackoverflow.com/a/3651042/6266737 – Jim Dec 02 '17 at 07:19
  • doesn't work if you provide one-digit week numbers, you should zero-pad it before. Also, I am not sure about the syntax, I think it should be: strtotime($year."-W".$week_number."-".$day) – Eugenio Jul 05 '19 at 10:33
  • Answer is from 2008 and still relevant. Works great! – Loosie94 Oct 11 '20 at 20:34
7

Since this question and the accepted answer were posted the DateTime classes make this much simpler to do:-

function daysInWeek($weekNum)
{
    $result = array();
    $datetime = new DateTime('00:00:00');
    $datetime->setISODate((int)$datetime->format('o'), $weekNum, 1);
    $interval = new DateInterval('P1D');
    $week = new DatePeriod($datetime, $interval, 6);

    foreach($week as $day){
        $result[] = $day->format('D d m Y H:i:s');
    }
    return $result;
}

var_dump(daysInWeek(24));

This has the added advantage of taking care of leap years etc..

See it working. Including the difficult weeks 1 and 53.

vascowhite
  • 18,120
  • 9
  • 61
  • 77
  • Unfortunately this doesn't work because setISODate() includes a time portion equal to that of today's time (i.e. not 0:00:00). Change to $result[] = $day->format('r'); and you'll see what I'm talking about. – Dalin Feb 12 '14 at 20:47
  • 2
    @Dalin I don't see how that means that it doesn't work. The OP never mentioned a time of day, just wanted the days. However, a small modification to the code resets all times to 00:00:00. – vascowhite Feb 13 '14 at 04:49
7

If you've got Zend Framework you can use the Zend_Date class to do this:

require_once 'Zend/Date.php';

$date = new Zend_Date();
$date->setYear(2008)
     ->setWeek(40)
     ->setWeekDay(1);

$weekDates = array();

for ($day = 1; $day <= 7; $day++) {
    if ($day == 1) {
        // we're already at day 1
    }
    else {
        // get the next day in the week
        $date->addDay(1);
    }

    $weekDates[] = date('Y-m-d', $date->getTimestamp());
}

echo '<pre>';
print_r($weekDates);
echo '</pre>';
Shane
  • 189
  • 1
  • 3
4

This calculation varies largely depending on where you live. For example, in Europe we start the week with a Monday, in US Sunday is the first day of the week. In UK week 1 is on Jan 1, others countries start week 1 on the week containing the first Thursday of the year.

You can find more general information at http://en.wikipedia.org/wiki/Week#Week_number

Martin Liesén
  • 1,308
  • 11
  • 14
2
$week_number = 40;
$year = 2008;

for($day=1; $day<=7; $day++)
{
    echo date('m/d/Y', strtotime($year."W".$week_number.$day))."\n";
}

This will fail if $week_number is less than 10.

//============Try this================//

$week_number = 40;
$year = 2008;

if($week_number < 10){
   $week_number = "0".$week_number;
}

for($day=1; $day<=7; $day++)
{
    echo date('m/d/Y', strtotime($year."W".$week_number.$day))."\n";
}

//==============================//
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Nicolas
  • 21
  • 1
2

This function will give the timestamps of days of the week in which $date is found. If $date isn't given, it assumes "now." If you prefer readable dates to timestamps, pass a date format into the second parameter. If you don't start your week on Monday (lucky), pass in a different day for the third parameter.

function week_dates($date = null, $format = null, $start = 'monday') {
  // is date given? if not, use current time...
  if(is_null($date)) $date = 'now';

  // get the timestamp of the day that started $date's week...
  $weekstart = strtotime('last '.$start, strtotime($date));

  // add 86400 to the timestamp for each day that follows it...
  for($i = 0; $i < 7; $i++) {
    $day = $weekstart + (86400 * $i);
    if(is_null($format)) $dates[$i] = $day;
    else $dates[$i] = date($format, $day);
  }

  return $dates;
}

So week_dates() should return something like...

Array ( 
  [0] => 1234155600 
  [1] => 1234242000 
  [2] => 1234328400 
  [3] => 1234414800 
  [4] => 1234501200
  [5] => 1234587600
  [6] => 1234674000
)
  • this function does not work correctly if the day was Monday !, this fix it if($currDay == 'Monday'){ $weekstart = strtotime("midnight",$date); }else{ $weekstart = strtotime('last '.$start, $date); } – FDI Apr 06 '14 at 16:20
1

Another code hehe:

public function getAllowedDays($year, $week) {
    $weekDaysArray = array();
    $dto = new \DateTime();
    $dto->setISODate($year, $week);

    for($i = 0; $i < 7; $i++) {
        array_push($weekDaysArray, $dto->format('Y-m-d'));
        $dto->modify("+1 days");
    }

    return $weekDaysArray;
}
Miton Leon
  • 274
  • 1
  • 5
  • 15
0

For those looking for the days of the week given the week number (1-52) Starting from a sunday then here is my little work around. Takes into account checking the week is in the right range and pads the values 1-9 to keep it all working.

$week = 2; $year = 2009;

$week = (($week >= 1) AND ($week <= 52))?($week-1):(1);

$dayrange  = array(7,1,2,3,4,5,6);

for($count=0; $count<=6; $count++) {
    $week = ($count == 1)?($week + 1): ($week);
    $week = str_pad($week,2,'0',STR_PAD_LEFT);
    echo date('d m Y', strtotime($year."W".$week.($dayrange[$count]))); }
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
0

I had the same question only using strftime instead of date as my starting point i.e. having derived a week number from strftime using %W I wanted to know the date range for that week - Monday to Sunday (or indeed any starting day). A review of several similar posts and in particular trying out a couple of the above approaches didn't get me to the solution I wanted. Of course I may have misunderstood something but I couldn't get what I wanted.

I would therefore like to share my solution.

My first thought was that given the description of strftime %W is:

week number of the current year, starting with the first Monday as the first day of the first week

if I established what the first Monday of each year is I could calculate an array of date ranges with an index equal to the value of %W. Thereafter I could call the function using strftime.

So here goes:

The Function:

<?php

/*
 *  function to establish scope of week given a week of the year value returned from strftime %W
 */

// note strftime %W reports 1/1/YYYY as wk 00 unless 1/1/YYYY is a monday when it reports wk 01
// note strtotime Monday [last, this, next] week - runs sun - sat

function date_Range_For_Week($W,$Y){

// where $W = %W returned from strftime
//       $Y = %Y returned from strftime

    // establish 1st day of 1/1/YYYY

    $first_Day_Of_Year = mktime(0,0,0,1,1,$Y);

    // establish the first monday of year after 1/1/YYYY    

    $first_Monday_Of_Year = strtotime("Monday this week",(mktime(0,0,0,1,1,$Y)));   

    // Check for week 00 advance first monday if found
    // We could use strtotime "Monday next week" or add 604800 seconds to find next monday
    // I have decided to avoid any potential strtotime overhead and do the arthimetic

    if (strftime("%W",$first_Monday_Of_Year) != "01"){
        $first_Monday_Of_Year += (60 * 60 * 24 * 7);
    }

    // create array to ranges for the year. Note 52 wks is the norm but it is possible to have 54 weeks
    // in a given yr therefore allow for this in array index

    $week_Start = array();
    $week_End = array();        

    for($i=0;$i<=53;$i++){

        if ($i == 0){   
            if ($first_Day_Of_Year != $first_Monday_Of_Year){
                $week_Start[$i] = $first_Day_Of_Year;
                $week_End[$i] = $first_Monday_Of_Year - (60 * 60 * 24 * 1);
            } else {
                // %W returns no week 00
                $week_Start[$i] = 0;
                $week_End[$i] = 0;                              
            }
            $current_Monday = $first_Monday_Of_Year;
        } else {
            $week_Start[$i] = $current_Monday;
            $week_End[$i] = $current_Monday + (60 * 60 * 24 * 6);
            // find next monday
            $current_Monday += (60 * 60 * 24 * 7);
            // test for end of year
            if (strftime("%W",$current_Monday) == "01"){ $i = 999; };
        }
    };

    $result = array("start" => strftime("%a on %d, %b, %Y", $week_Start[$W]), "end" => strftime("%a on %d, %b, %Y", $week_End[$W]));

    return $result;

    }   

?>

Example:

// usage example

//assume we wish to find the date range of a week for a given date July 12th 2011

$Y = strftime("%Y",mktime(0,0,0,7,12,2011));
$W = strftime("%W",mktime(0,0,0,7,12,2011));

// use dynamic array variable to check if we have range if so get result if not run function

$date_Range = date_Range . "$Y";

isset(${$date_Range}) ? null : ${$date_Range} = date_Range_For_Week($W, $Y);

echo "Date sought: " . strftime(" was %a on %b %d, %Y, %X time zone: %Z",mktime(0,0,0,7,12,2011)) . "<br/>";
echo "start of week " . $W . " is " . ${$date_Range}["start"] . "<br/>";
echo "end of week " . $W . " is " . ${$date_Range}["end"];

Output:

> Date sought: was Tue on Jul 12, 2011, 00:00:00 time zone: GMT Daylight
> Time start of week 28 is Mon on 11, Jul, 2011 end of week 28 is Sun on
> 17, Jul, 2011

I have tested this over several years including 2018 which is the next year when 1/1/2018 = Monday. Thus far seems to deliver the correct date range.

So I hope that this helps.

Regards

codepuppy
  • 1,130
  • 2
  • 15
  • 25
0

Another solution:

//$date Date in week
//$start Week start (out)
//$end Week end (out)

function week_bounds($date, &$start, &$end) {
    $date = strtotime($date);
    $start = $date;
    while( date('w', $start)>1 ) {
        $start -= 86400;
    }
    $end = date('Y-m-d', $start + (6*86400) );
    $start = date('Y-m-d', $start);
}

Example:

week_bounds("2014/02/10", $start, $end);
echo $start."<br>".$end;

Out:

2014-02-10
2014-02-16
joan16v
  • 5,055
  • 4
  • 49
  • 49
0
$year      = 2016; //enter the year
$wk_number = 46;   //enter the weak nr

$start = new DateTime($year.'-01-01 00:00:00');
$end   = new DateTime($year.'-12-31 00:00:00');

$start_date = $start->format('Y-m-d H:i:s');

$output[0]= $start;    
$end   = $end->format('U');    
$x = 1;

//create array full of data objects
for($i=0;;$i++){
    if($i == intval(date('z',$end)) || $i === 365){
        break;
    }
    $a = new DateTime($start_date);
    $b = $a->modify('+1 day');
    $output[$x]= $a;        
    $start_date = $b->format('Y-m-d H:i:s');
    $x++;
}    

//create a object to use
for($i=0;$i<count($output);$i++){
    if(intval ($output[$i]->format('W')) === $wk_number){
        $output_[$output[$i]->format('N')]        = $output[$i];
    }
}

$dayNumberOfWeek = 1; //enter the desired day in 1 = Mon -> 7 = Sun

echo '<pre>';
print_r($output_[$dayNumberOfWeek]->format('Y-m-d'));
echo '</pre>';

use as date() object from php date php

0

I found a problem with this solution. I had to zero-pad the week number or else it was breaking.

My solution looks like this now:

$week_number = 40;
$year = 2008;
for($day=1; $day<=7; $day++)
{
    echo date('m/d/Y', strtotime($year."W".str_pad($week_number,2,'0',STR_PAD_LEFT).$day))."\n";
}
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Yashvit
  • 2,337
  • 3
  • 25
  • 32
0

Period based on week numbers and days

Some countries (like Scandinavian countries and Germany) use week numbers, as a practical way of booking holidays, meetings etc. This function can based on week number start day and period length in days deliver a text message regarding the period.

function MakePeriod($year,$Week,$StartDay,$NumberOfDays, $lan='DK'){
    //Please note that start dates in january of week 53 must be entered as "the year before"
    switch($lan){
    case "NO":
        $WeekDays=['mandag','tirsdag','onsdag','torsdag','fredag','lørdag','søndag'];
        $the=" den ";
        $weekName="Uke ";
        $dateformat="j/n Y";
    break;      
    case "DK":
        $WeekDays=['mandag','tirsdag','onsdag','torsdag','fredag','lørdag','søndag'];
        $the=" den ";
        $weekName="Uge ";
        $dateformat="j/n Y";
    break;
    case "SV":
        $WeekDays=['måndag','tisdag','onsdag','torsdag','fredag','lördag','söndag'];
        $the=" den ";
        $weekName="Vecka ";
        $dateformat="j/n Y";
    break;
    case "GE":
        $WeekDays=['Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag','Sonntag'];
        $the=" die ";
        $weekName="Woche ";
        $dateformat="j/n Y";
    break;
    case "EN":
    case "US":  
        $WeekDays=['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'];
        $the=" the ";
        $weekName="Week ";
        $dateformat="n/j/Y";
    break;  
    }   
    $EndDay= (($StartDay-1+$NumberOfDays) % 7)+1;
    $ExtraDays= $NumberOfDays % 7;
    $FirstWeek=$Week;
    $LastWeek=$Week;    
    $NumberOfWeeks=floor($NumberOfDays / 7) ;
    $LastWeek=$Week+$NumberOfWeeks;

    if($StartDay+$ExtraDays>7){
        $LastWeek++;
    }       

    if($FirstWeek<10) $FirstWeek='0'.$FirstWeek;
    if($LastWeek<10) $LastWeek='0'.$LastWeek;

    
    $date1 = date( $dateformat, strtotime($year."W".$FirstWeek.$StartDay) ); // First day of week

    $date2 = date( $dateformat, strtotime($year."W".$LastWeek.$EndDay) ); // Last day of week

    if($LastWeek>53){
        $LastWeek=$LastWeek-53;
        $year++;
        if($LastWeek<10) $LastWeek='0'.$LastWeek;
        $date2 = date( $dateformat, strtotime($year."W".$LastWeek.$EndDay) );
    }
    $EndDayName=$WeekDays[$EndDay-1];
    $StartDayName=$WeekDays[$StartDay-1];
    $retval= " $weekName $Week $StartDayName  $the $date1 - $EndDayName $the $date2 ";
    return $retval;     
    
}

Test:

$Year=2021;
$Week=22;   
$StartDay=4;    
$NumberOfDays=3;
$Period=MakePeriod($Year,$Week,$StartDay,$NumberOfDays,"DK");
echo $Period;

Uge 22 torsdag den 3/6 2021 - søndag den 6/6 2021

oleviolin
  • 894
  • 10
  • 10
-1
    <?php
    $iWeeksAgo = 5;// need weeks ago
    $sWeekDayStartOn = 0;// 0 - Sunday, 1 - Monday, 2 - Tuesday
    $aWeeksDetails = getWeekDetails($iWeeksAgo, $sWeekDayStartOn);

    print_r($aWeeksDetails);
    die('end of line of getWeekDetails ');

    function getWeekDetails($iWeeksAgo, $sWeekDayStartOn){
        $date = new DateTime();
        $sCurrentDate = $date->format('W, Y-m-d, w');
        #echo 'Current Date (Week of the year, YYYY-MM-DD, day of week ): ' . $sCurrentDate . "\n";

        $iWeekOfTheYear = $date->format('W');// Week of the Year i.e. 19-Feb-2014 = 08
        $iDayOfWeek = $date->format('w');// day of week for the current month i.e. 19-Feb-2014 = 4
        $iDayOfMonth = $date->format('d'); // date of the month i.e. 19-Feb-2014 = 19

        $iNoDaysAdd = 6;// number of days adding to get last date of the week i.e. 19-Feb-2014  + 6 days = 25-Feb-2014

        $date->sub(new DateInterval("P{$iDayOfWeek}D"));// getting start date of the week
        $sStartDateOfWeek = $date->format('Y-m-d');// getting start date of the week

        $date->add(new DateInterval("P{$iNoDaysAdd}D"));// getting end date of the week
        $sEndDateOfWeek = $date->format('Y-m-d');// getting end date of the week

        $iWeekOfTheYearWeek = (string) $date->format('YW');//week of the year
        $iWeekOfTheYearWeekWithPeriod = (string) $date->format('Y-W');//week of the year with year

        //To check uncomment
        #echo "Start Date / End Date of Current week($iWeekOfTheYearWeek), week with - ($iWeekOfTheYearWeekWithPeriod) : " . $sStartDateOfWeek . ',' . $sEndDateOfWeek . "\n";

        $iDaysAgo = ($iWeeksAgo*7) + $iNoDaysAdd + $sWeekDayStartOn;// getting 4 weeks ago i.e. no. of days to substract

        $date->sub(new DateInterval("P{$iDaysAgo}D"));// getting 4 weeks ago i.e. no. of days to substract
        $sStartDateOfWeekAgo = $date->format('Y-m-d');// getting 4 weeks ago start date i.e. 19-Jan-2014

        $date->add(new DateInterval("P{$iNoDaysAdd}D")); // getting 4 weeks ago end date i.e. 25-Jan-2014
        $sEndDateOfWeekAgo = $date->format('Y-m-d');// getting 4 weeks ago start date i.e. 25-Jan-2014

        $iProccessedWeekAgoOfTheYear = (string) $date->format('YW');//ago week of the year
        $iProccessedWeekOfTheYearWeekAgo = (string) $date->format('YW');//ago week of the year with year
        $iProccessedWeekOfTheYearWeekWithPeriodAgo = (string) $date->format('Y-W');//ago week of the year with year

        //To check uncomment
        #echo "Start Date / End Date of week($iProccessedWeekOfTheYearWeekAgo), week with - ($iProccessedWeekOfTheYearWeekWithPeriodAgo) ago: " . $sStartDateOfWeekAgo . ',' . $sEndDateOfWeekAgo . "\n";

        $aWeeksDetails = array ('weeksago' => $iWeeksAgo, 'currentweek' => $iWeekOfTheYear, 'currentdate' => $sCurrentDate, 'startdateofcurrentweek' => $sStartDateOfWeek,  'enddateofcurrentweek' => $sEndDateOfWeek,
                                'weekagoyearweek' => $iProccessedWeekAgoOfTheYear, 'startdateofagoweek' => $sStartDateOfWeekAgo,  'enddateofagoweek' => $sEndDateOfWeekAgo);

        return $aWeeksDetails;
    }
?> 
Dhananjay
  • 1
  • 1
  • 2
    Welcome to Stack Overflow! Thanks for posting your answer! Please note that you should post the essential parts of the answer here, on this site, or your post risks being deleted [See the FAQ where it mentions answers that are 'barely more than a link'.](http://stackoverflow.com/faq#deletion) You may still include the link if you wish, but only as a 'reference'. The answer should stand on its own without needing the link. – Taryn Feb 19 '14 at 11:19