【问题标题】:Calculating days of week given a week number给定周数计算星期几
【发布时间】:2008-10-09 08:42:11
【问题描述】:

给定一个星期数,例如date -u +%W,从星期一开始,那一周的天数如何计算?

第 40 周的示例 rfc-3339 输出:

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

【问题讨论】:

    标签: php date


    【解决方案1】:

    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 中,改编自 this post 上的 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;
    }
    

    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
    )
    

    【讨论】:

    • 该输入与指定不符。例如,输入将是“41”。
    • 谢谢,这里周一早上大脑的坏情况,没有正确阅读。用更短的代码 sn-p 更新了答案!
    • 愚蠢的错字,到目前为止还没有早上好!现已修复,感谢现场。
    • 我更喜欢这样: echo date('Y-m-d', strtotime(date("Y")."W".date("W").$day))."\n ";无论如何,非常感谢您的回答。
    • eeek,刚刚注意到:php -r "echo date("W");"date -u +%W 41 != 40
    【解决方案2】:

    如果你有 Zend 框架,你可以使用 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('Y-m-d', $date->getTimestamp());
    }
    
    echo '<pre>';
    print_r($weekDates);
    echo '</pre>';
    

    【讨论】:

      【解决方案3】:

      自从发布了这个问题和接受的答案后,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 d m Y H:i:s');
          }
          return $result;
      }
      
      var_dump(daysInWeek(24));
      

      这具有照顾闰年等的额外优势。

      See it working。包括艰难的第 1 周和第 53 周。

      【讨论】:

      • 不幸的是,这不起作用,因为 setISODate() 包含的时间部分等于今天的时间(即不是 0:00:00)。更改为 $result[] = $day->format('r');你会明白我在说什么。
      • @Dalin 我不明白这意味着它不起作用。 OP从未提及一天中的某个时间,只是想要这些日子。但是,对代码的一个小修改将所有时间重置为 00:00:00。
      【解决方案4】:

      此计算在很大程度上取决于您居住的地方。例如,在欧洲,我们从星期一开始一周,在美国,星期日是一周的第一天。在英国,第 1 周是 1 月 1 日,其他国家/地区从包含一年中第一个星期四的那一周开始第 1 周。

      您可以在http://en.wikipedia.org/wiki/Week#Week_number找到更多一般信息

      【讨论】:

        【解决方案5】:

        此函数将给出找到 $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
        )
        

        【讨论】:

        • 如果当天是星期一,这个函数不能正常工作!,这个修复它 if($currDay == 'Monday'){ $weekstart = strtotime("midnight",$date); }else{ $weekstart = strtotime('last '.$start, $date); }
        【解决方案6】:
        $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";
        }
        
        //==============================//
        

        【讨论】:

        • 这应该是公认的答案,因为它可以正常工作!
        【解决方案7】:

        另一个代码嘿嘿:

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

        【讨论】:

          【解决方案8】:

          我发现此解决方案存在问题。 我必须将周数填零,否则它会中断。

          我的解决方案现在看起来像这样:

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

          【讨论】:

            【解决方案9】:

            对于那些在给定周数 (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('d m Y', strtotime($year."W".$week.($dayrange[$count]))); }
            

            【讨论】:

            • 未能返回 $week #1 上一年的日期。
            【解决方案10】:

            我有同样的问题,只使用 strftime 而不是日期作为我的起点,即使用 %W 从 strftime 导出周数我想知道该周的日期范围 - 周一到周日(或者实际上是任何开始日)。对几个类似帖子的评论,特别是尝试了上述几种方法并没有让我得到我想要的解决方案。当然,我可能误解了一些东西,但我无法得到我想要的。

            因此,我想分享我的解决方案。

            我的第一个想法是,鉴于 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 年,即 2018 年 1 月 1 日 = 星期一的下一年。到目前为止,似乎提供了正确的日期范围。

            所以我希望这会有所帮助。

            问候

            【讨论】:

              【解决方案11】:

              另一种解决方案:

              //$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);
              }
              

              例子:

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

              输出:

              2014-02-10
              2014-02-16
              

              【讨论】:

                【解决方案12】:
                $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>';
                

                在 php 中用作 date() 对象 date php

                【讨论】:

                  【解决方案13】:

                  基于周数和天数的周期

                  一些国家(如斯堪的纳维亚国家和德国)使用周数,作为预订假期、会议等的实用方式。此功能可以根据周数开始日期和周期长度(以天为单位)发送有关周期的短信。

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

                  测试:

                  $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

                  【讨论】:

                    【解决方案14】:
                        <?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;
                        }
                    ?> 
                    

                    【讨论】:

                    • 欢迎来到 Stack Overflow!感谢您发布您的答案!请注意,您应该在此处、此站点上发布答案的基本部分,否则您的帖子有被删除的风险See the FAQ where it mentions answers that are 'barely more than a link'. 如果您愿意,您仍然可以包含该链接,但仅作为“参考”。答案应该是独立的,不需要链接。
                    猜你喜欢
                    • 2018-07-14
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-09-04
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-05-10
                    • 1970-01-01
                    相关资源
                    最近更新 更多