Расчет дней недели с указанием номера недели

Учитывая номер недели, например, date -u +%W , как вы рассчитываете дни на этой неделе, начиная с понедельника?

Пример вывода rfc-3339 за неделю 40:

 2008-10-06 2008-10-07 2008-10-08 2008-10-09 2008-10-10 2008-10-11 2008-10-12 

PHP

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


Ниже было сообщение, потому что я был идиотом, который не читал вопрос правильно, но получит даты в неделю, начиная с понедельника, учитывая дату, а не номер недели.

В PHP , адаптированном из этого сообщения на странице руководства по дате PHP :

 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('Ym-d',$monday+($seconds_in_a_day*$i)); } return $dates; } 

Выходной week_from_monday('07-10-2008') дает:

 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 ) 

Если у вас есть Zend Framework, вы можете использовать класс Zend_Date для этого:

 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('Ym-d', $date->getTimestamp()); } echo '<pre>'; print_r($weekDates); echo '</pre>'; - 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('Ym-d', $date->getTimestamp()); } echo '<pre>'; print_r($weekDates); echo '</pre>'; - 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('Ym-d', $date->getTimestamp()); } echo '<pre>'; print_r($weekDates); echo '</pre>'; 

Поскольку этот вопрос и принятый ответ были опубликованы, классы DateTime делают это намного проще:

 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 dm YH:i:s'); } return $result; } var_dump(daysInWeek(24)); 

У этого есть дополнительное преимущество, заботясь о високосных годах и т. Д.

Смотрите, как работает . Включая трудные недели 1 и 53.

Этот расчет во многом зависит от того, где вы живете. Например, в Европе мы начинаем неделю с понедельника, в США воскресенье – первый день недели. В Великобритании неделя 1 – 1 января, другие страны начинают неделю 1 на неделе, содержащей первый четверг года.

Более подробную информацию вы можете найти на странице http://en.wikipedia.org/wiki/Week#Week_number

Эта функция даст отметки времени недели недели, в которой найдена дата $ date. Если $ date не задана, она принимает «сейчас». Если вы предпочитаете читаемые даты для временных меток, передайте формат даты во второй параметр. Если вы не начнете свою неделю в понедельник (повезет), перейдите в другой день для третьего параметра.

 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; } 

Поэтому week_dates () должен возвращать что-то вроде …

 Array ( [0] => 1234155600 [1] => 1234242000 [2] => 1234328400 [3] => 1234414800 [4] => 1234501200 [5] => 1234587600 [6] => 1234674000 ) 
 $week_number = 40; $year = 2008; for($day=1; $day<=7; $day++) { echo date('m/d/Y', strtotime($year."W".$week_number.$day))."\n"; } 

Это произойдет, если $week_number меньше 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"; } //==============================// 

Другой код хехе:

 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('Ym-d')); $dto->modify("+1 days"); } return $weekDaysArray; } 

Я нашел проблему с этим решением. Я должен был пропустить номер недели, иначе он сломался.

Теперь мое решение выглядит так:

 $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"; } 

Для тех, кто ищет дни недели, учитывая номер недели (1-52). Начиная с воскресенья, вот моя маленькая работа. Учитывает, что неделя находится в правильном диапазоне и заполняет значения 1-9, чтобы все это работало.

 $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('dm Y', strtotime($year."W".$week.($dayrange[$count]))); } 

У меня был тот же вопрос, только используя strftime вместо даты в качестве отправной точки, т. Е. Получив номер недели из strftime, используя% WI, хотел знать диапазон дат на эту неделю – с понедельника по воскресенье (или даже в любой начальный день). Обзор нескольких подобных должностей и, в частности, опробование нескольких вышеуказанных подходов не привел меня к решению, которое я хотел. Конечно, я, возможно, что-то неправильно понял, но я не мог получить то, что хотел.

Поэтому я хотел бы поделиться своим решением.

Моя первая мысль заключалась в том, что, учитывая описание strftime% W,

недельный номер текущего года, начиная с первого понедельника в качестве первого дня первой недели

если я установил, что первый понедельник каждого года, я мог бы рассчитать массив диапазонов дат с индексом, равным значению% W. После этого я мог бы вызвать функцию, используя strftime.

Так вот:

Функция:

 <?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; } ?> 

Пример:

 // 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"]; 

Вывод:

 > 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 

Я тестировал это в течение нескольких лет, включая 2018 год, который следующий год, когда 1/1/2018 = понедельник. До сих пор, кажется, доставлял правильный диапазон дат.

Поэтому я надеюсь, что это поможет.

С уважением

Другое решение:

 //$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('Ym-d', $start + (6*86400) ); $start = date('Ym-d', $start); } 

Пример:

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

Вне:

 2014-02-10 2014-02-16 
 $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('Ymd 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('Ymd 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('Ym-d')); echo '</pre>'; 

использовать как объект date () с php date php

  <?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, Ymd, w'); #echo 'Current Date (Week of the year, YYYY-MM-DD, day of week ): ' . $sCurrentDate . "\n"; $iWeekOfTheYear = $date->format('W');// Week of the Year ie 19-Feb-2014 = 08 $iDayOfWeek = $date->format('w');// day of week for the current month ie 19-Feb-2014 = 4 $iDayOfMonth = $date->format('d'); // date of the month ie 19-Feb-2014 = 19 $iNoDaysAdd = 6;// number of days adding to get last date of the week ie 19-Feb-2014 + 6 days = 25-Feb-2014 $date->sub(new DateInterval("P{$iDayOfWeek}D"));// getting start date of the week $sStartDateOfWeek = $date->format('Ym-d');// getting start date of the week $date->add(new DateInterval("P{$iNoDaysAdd}D"));// getting end date of the week $sEndDateOfWeek = $date->format('Ym-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 ie no. of days to substract $date->sub(new DateInterval("P{$iDaysAgo}D"));// getting 4 weeks ago ie no. of days to substract $sStartDateOfWeekAgo = $date->format('Ym-d');// getting 4 weeks ago start date ie 19-Jan-2014 $date->add(new DateInterval("P{$iNoDaysAdd}D")); // getting 4 weeks ago end date ie 25-Jan-2014 $sEndDateOfWeekAgo = $date->format('Ym-d');// getting 4 weeks ago start date ie 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; } ?>