【问题标题】:Get week number in month from date in PHP?从PHP中的日期获取月份中的周数?
【发布时间】:2015-09-16 18:18:28
【问题描述】:

我有一个随机日期数组(不是来自 MySQL)。我需要按周将它们分组为第 1 周、第 2 周等等,直到第 5 周。

我拥有的是这样的:

$dates = array('2015-09-01','2015-09-05','2015-09-06','2015-09-15','2015-09-17');

我需要的是一个通过提供日期来获取月份周数的函数。

我知道我可以通过做 date('W',strtotime('2015-09-01')); 但是这个周数是年份(1-52)之间的数字,但我只需要当月的周数,例如2015 年 9 月有 5 周:

  • 第 1 周 = 第 1 到第 5
  • 第 2 周 = 第 6 至 12 日
  • 第 3 周 = 13 日至 19 日
  • 第 4 周 = 20 日至 26 日
  • 第 5 周 = 27 日至 30 日

我应该能够通过提供日期来获得第 1 周 例如

$weekNumber = getWeekNumber('2015-09-01') //output 1;
$weekNumber = getWeekNumber('2015-09-17') //output 3;

【问题讨论】:

  • 请澄清您的问题。

标签: php arrays date week-number


【解决方案1】:

我觉得这种关系应该是真的,并且派上用场:

Week of the month = Week of the year - Week of the year of first day of month + 1

我们还需要确保正确处理与上一年“重叠”的周 - 如果 1 月 1 日在第 52 周或第 53 周,则应计为第 0 周。以类似的方式,如果 12 月的一天是在明年的第一周,应该算作53。(这个答案的以前版本没有正确做到这一点。)

<?php

function weekOfMonth($date) {
    //Get the first day of the month.
    $firstOfMonth = strtotime(date("Y-m-01", $date));
    //Apply above formula.
    return weekOfYear($date) - weekOfYear($firstOfMonth) + 1;
}

function weekOfYear($date) {
    $weekOfYear = intval(date("W", $date));
    if (date('n', $date) == "1" && $weekOfYear > 51) {
        // It's the last week of the previos year.
        return 0;
    }
    else if (date('n', $date) == "12" && $weekOfYear == 1) {
        // It's the first week of the next year.
        return 53;
    }
    else {
        // It's a "normal" week.
        return $weekOfYear;
    }
}

// A few test cases.
echo weekOfMonth(strtotime("2020-04-12")) . " "; // 2
echo weekOfMonth(strtotime("2020-12-31")) . " "; // 5
echo weekOfMonth(strtotime("2020-01-02")) . " "; // 1
echo weekOfMonth(strtotime("2021-01-28")) . " "; // 5
echo weekOfMonth(strtotime("2018-12-31")) . " "; // 6

要获得从星期日开始的星期,只需将 date("W", ...) 替换为 strftime("%U", ...)

【讨论】:

  • 这将产生一个 PHP 通知:遇到格式不正确的数值。但是,使用 strtotime($date) 时不会发生这种情况
  • 一月的时候效果不好,1月1日正好是上一年。
  • @CiprianIonescu 感谢您指出这一点。确实,例如2021-01-18 给出了错误的答案。我添加了一条通知,稍后将尝试通过修复来更新答案。再次感谢您!
  • @CiprianIonescu 我现在已经解决了你指出的问题。
  • 我认为现在可行。感谢您的更正。从 1970 年到 2038 年,我现在得到的结果与我的函数相同。
【解决方案2】:

你可以使用下面的函数,完整注释:

/**
 * Returns the number of week in a month for the specified date.
 *
 * @param string $date
 * @return int
 */
function weekOfMonth($date) {
    // estract date parts
    list($y, $m, $d) = explode('-', date('Y-m-d', strtotime($date)));
    
    // current week, min 1
    $w = 1;
    
    // for each day since the start of the month
    for ($i = 1; $i < $d; ++$i) {
        // if that day was a sunday and is not the first day of month
        if ($i > 1 && date('w', strtotime("$y-$m-$i")) == 0) {
            // increment current week
            ++$w;
        }
    }
    
    // now return
    return $w;
}

【讨论】:

  • 这也没有给出正确的结果。'2015-09-06'应该是第二周而不是第一周。
  • 我认为将 $i = 1; $i &lt;= $d; ++$i 更改为 $i = 1; $i &lt; $d; ++$i 以获得完美的结果..
  • 你为什么会这样建议?有没有失败的具体案例?
  • 我认为@Asif 的建议是对的, 2022-01-31, 最大周数为 6 .
  • 我修复了这个功能,谢谢提示。
【解决方案3】:

正确的方法是

function weekOfMonth($date) {
    $firstOfMonth = date("Y-m-01", strtotime($date));
    return intval(date("W", strtotime($date))) - intval(date("W", strtotime($firstOfMonth)));
}

【讨论】:

    【解决方案4】:

    我自己创建了这个函数,它似乎可以正常工作。如果其他人有更好的方法,请分享..这是我所做的。

    function weekOfMonth($qDate) {
        $dt = strtotime($qDate);
        $day  = date('j',$dt);
        $month = date('m',$dt);
        $year = date('Y',$dt);
        $totalDays = date('t',$dt);
        $weekCnt = 1;
        $retWeek = 0;
        for($i=1;$i<=$totalDays;$i++) {
            $curDay = date("N", mktime(0,0,0,$month,$i,$year));
            if($curDay==7) {
                if($i==$day) {
                    $retWeek = $weekCnt+1;
                }
                $weekCnt++;
            } else {
                if($i==$day) {
                    $retWeek = $weekCnt;
                }
            }
        }
        return $retWeek;
    }
    


    echo weekOfMonth('2015-09-08') // gives me 2;
    

    【讨论】:

    • 你能解释一下为什么$weekCnt被初始化为1吗?
    • 如果我写 echo weekOfMonth('2017-10-01'); 它输出 2。我认为它应该是 1。
    【解决方案5】:
    function getWeekOfMonth(DateTime $date) {
        $firstDayOfMonth = new DateTime($date->format('Y-m-1'));
    
        return ceil(($firstDayOfMonth->format('N') + $date->format('j') - 1) / 7);
    }
    

    Goendg solution 不适用于 2016-10-31。

    【讨论】:

      【解决方案6】:
      function weekOfMonth($strDate) {
        $dateArray = explode("-", $strDate);
        $date = new DateTime();
        $date->setDate($dateArray[0], $dateArray[1], $dateArray[2]);
        return floor((date_format($date, 'j') - 1) / 7) + 1;  
      }
      

      weekOfMonth ('2015-09-17') // 返回 3

      【讨论】:

      • 欢迎来到 Stack Overflow!请不要把你的源代码扔在这里。友善一点,并尝试对您的答案进行漂亮的描述,以便其他人会喜欢并支持它。见:How do I write a good answer?
      【解决方案7】:

      给定firstWday 中每月第一天的 time_t wday(0=星期日到 6=星期六),这将返回该月内(基于星期日)的周数:

      weekOfMonth = floor((dayOfMonth + firstWday - 1)/7) + 1 
      

      翻译成PHP:

      function weekOfMonth($dateString) {
        list($year, $month, $mday) = explode("-", $dateString);
        $firstWday = date("w",strtotime("$year-$month-1"));
        return floor(($mday + $firstWday - 1)/7) + 1;
      }
      

      【讨论】:

        【解决方案8】:

        您还可以使用这个简单的公式来查找月份中的星期

        $currentWeek = ceil((date("d",strtotime($today_date)) - date("w",strtotime($today_date)) - 1) / 7) + 1;
        

        算法:

        日期 = '2018-08-08' => Y-m-d

        1. 找出一个月中的哪一天,例如。 08
        2. 找出星期几的数字表示减去 1(星期几),例如。 (3-1)
        3. 取差并存储在结果中
        4. 从结果中减去 1
        5. 将其除以 7 得到结果,并将结果的值设为上限
        6. 将结果加 1,例如。 ceil(( 08 - 3 ) - 1 ) / 7) + 1 = 2

        【讨论】:

          【解决方案9】:

          我的功能。主要思想:我们将计算从该月的第一个日期到当前日期的周数。当前的周数将是下一个周数。适用于规则:“星期从星期一开始”(对于基于星期日的类型,我们需要转换递增算法)

          function GetWeekNumberOfMonth ($date){
              echo $date -> format('d.m.Y');
              //define current year, month and day in numeric
              $_year = $date -> format('Y');
              $_month = $date -> format('n');
              $_day = $date -> format('j');
              $_week = 0; //count of weeks passed
              for ($i = 1; $i < $_day; $i++){
                  echo "\n\n-->";
                  $_newDate = mktime(0,0,1, $_month, $i, $_year);
                  echo "\n";
                  echo date("d.m.Y", $_newDate);
                  echo "-->";
                  echo date("N", $_newDate);
                  //on sunday increasing weeks passed count
                  if (date("N", $_newDate) == 7){
                      echo "New week";
                      $_week += 1;
                  }
          
              }
              return $_week + 1; // as we are counting only passed weeks the current one would be on one higher
          }
          
          $date = new DateTime("2019-04-08");
          echo "\n\nResult: ". GetWeekNumberOfMonth($date);
          

          【讨论】:

            【解决方案10】:
            $month = 6;
            $year = 2021;           
            $week = date("W", strtotime($year . "-" . $month ."-01"));
            
            $str='';
            $str .= date("d-m-Y", strtotime($year . "-" . $month ."-01")) ."to";
            $unix = strtotime($year."W".$week ."+1 week");
            while(date("m", $unix) == $month){
             $str .= date("d-m-Y", $unix-86400) . "|";
             $str .= date("d-m-Y", $unix) ."to"; 
             $unix = $unix + (86400*7);
            }
            $str .= date("d-m-Y", strtotime("last day of ".$year . "-" . $month));
            
            $weeks_ar = explode('|',$str);
            echo '<pre>'; print_r($weeks_ar);
            

            工作正常。

            【讨论】:

              【解决方案11】:
                  // Current week of the month starts with Sunday
               
                  $first_day_of_the_week = 'Sunday';
                  $start_of_the_week1    = strtotime("Last $first_day_of_the_week");     
                  
                  if (strtolower(date('l')) === strtolower($first_day_of_the_week)) {
                       $start_of_the_week1 = strtotime('today');
                   }
                   $end_of_the_week1   = $start_of_the_week1 + (60 * 60 * 24 * 7) - 1;
              
              // Get the date format
              print date('Y-m-d', $start_of_the_week1) . ' 00:00:00';
              print date('Y-m-d', $end_of_the_week1) . ' 23:59:59';
              

              【讨论】:

                【解决方案12】:
                // self::DAYS_IN_WEEK = 7;
                function getWeeksNumberOfMonth(): int
                {
                    $currentDate            = new \DateTime();
                    $dayNumberInMonth       = (int) $currentDate->format('j');
                    $dayNumberInWeek        = (int) $currentDate->format('N');
                    $dayNumberToLastSunday  = $dayNumberInMonth - $dayNumberInWeek;
                    $daysCountInFirstWeek   = $dayNumberToLastSunday % self::DAYS_IN_WEEK;
                    $weeksCountToLastSunday = ($dayNumberToLastSunday - $daysCountInFirstWeek) / self::DAYS_IN_WEEK;
                
                    $weeks = [];
                    array_push($weeks, $daysCountInFirstWeek);
                    for ($i = 0; $i < $weeksCountToLastSunday; $i++) {
                        array_push($weeks, self::DAYS_IN_WEEK);
                    }
                    array_push($weeks, $dayNumberInWeek);
                
                    if (array_sum($weeks) !== $dayNumberInMonth) {
                        throw new Exception('Logic is not valid');
                    }
                
                    return count($weeks);
                }
                

                短变体:

                (int) (new \DateTime())->format('W') - (int) (new \DateTime('first day of this month'))->format('W') + 1;
                

                【讨论】:

                • 这个答案缺少教育解释。
                • 查看变量名
                • 良好的变量命名约定!= 教育解释。
                【解决方案13】:

                有很多解决方案,但这是我的一个解决方案,在大多数情况下运行良好。

                function current_week ($date = NULL) {
                    if($date) {
                        if(is_numeric($date) && ctype_digit($date) && strtotime(date('Y-m-d H:i:s',$date)) === (int)$date)
                            $unix_timestamp = $date;
                        else
                            $unix_timestamp = strtotime($date);
                    } else $unix_timestamp = time();
                
                    return (ceil((date('d', $unix_timestamp) - date('w', $unix_timestamp) - 1) / 7) + 1);
                }
                

                如果您没有传递任何值,它接受 unix 时间戳、正常日期或从 time() 返回当前周。

                享受吧!

                【讨论】:

                  【解决方案14】:

                  我知道这是一篇旧帖子,但我有个主意!

                  $datetime0 = date_create("1970-01-01");
                  $datetime1 = date_create(date("Y-m-d",mktime(0,0,0,$m,"01",$Y)));
                  $datetime2 = date_create(date("Y-m-d",mktime(0,0,0,$m,$d,$Y)));
                  
                  $interval1 = date_diff($datetime0, $datetime1);
                  $daysdiff1= $interval1->format('%a');
                  
                  $interval2 = date_diff($datetime0, $datetime2);
                  $daysdiff2= $interval2->format('%a');
                  
                  $week1=round($daysdiff1/7);
                  $week2=round($daysdiff2/7);
                  
                  $WeekOfMonth=$week2-$week1+1;
                  

                  【讨论】:

                  • 这个答案缺少教育解释。
                  【解决方案15】:
                  $date = new DateTime('first Monday of this month');
                  $thisMonth = $date->format('m');
                  $mondays_arr = [];
                  
                  // Get all the Mondays in the current month and store in array
                  while ($date->format('m') === $thisMonth) {
                      //echo $date->format('Y-m-d'), "\n";
                      $mondays_arr[] = $date->format('d');
                      $date->modify('next Monday');
                  }
                  
                  // Get the day of the week (1-7 from monday to sunday)
                  $day_of_week = date('N') - 1;
                  
                  // Get the day of month (1 to 31) 
                  $current_week_monday_date = date('j') - $day_of_week;
                  
                  /*$day_of_week = date('N',mktime(0, 0, 0, 2, 11, 2020)) - 1;
                  $current_week_monday_date = date('j',mktime(0, 0, 0, 2, 11, 2020)) - $day_of_week;*/
                  
                  $week_no = array_search($current_week_monday_date,$mondays_arr) + 1;
                  echo "Week No: ". $week_no;
                  

                  【讨论】:

                    【解决方案16】:

                    这个函数如何利用 PHP 的相对日期? 此函数假定星期在星期六结束。但这很容易改变。

                    function get_weekNumMonth($date) {
                        $CI = &get_instance();
                        $strtotimedate = strtotime($date);
                        $firstweekEnd = date('j', strtotime("FIRST SATURDAY OF " . date("F", $strtotimedate) . " " . date("Y", $strtotimedate)));
                        $cutoff = date('j', strtotime($date));
                        $weekcount = 1;
                        while ($cutoff > $firstweekEnd) {
                            $weekcount++;
                            $firstweekEnd += 7; // move to next week
                        }
                        return $weekcount;
                    }
                    

                    【讨论】:

                      【解决方案17】:

                      此函数返回当前月份的整数周数。周总是从星期一开始,计数总是从 1 开始。

                      function weekOfmonth(DateTime $date)
                      {
                        $dayFirstMonday = date_create('first monday of '.$date->format('F Y'))->format('j');
                        return (int)(($date->format('j') - $dayFirstMonday +7)/7) + ($dayFirstMonday == 1 ? 0 : 1);
                      }
                      

                      使用示例

                      echo weekOfmonth(new DateTime("2020-04-12"));  //2
                      

                      以@Anders 接受的解决方案作为参考,对 1900 年至 2038 年的所有日子进行测试:

                      //reference functions
                      //integer $date (Timestamp) 
                      function weekOfMonthAnders($date) {
                          //Get the first day of the month.
                          $firstOfMonth = strtotime(date("Y-m-01", $date));
                          //Apply above formula.
                          return weekOfYear($date) - weekOfYear($firstOfMonth) + 1;
                      }
                      
                      function weekOfYear($date) {
                          $weekOfYear = intval(date("W", $date));
                          if (date('n', $date) == "1" && $weekOfYear > 51) {
                              // It's the last week of the previos year.
                              return 0;
                          }
                          else if (date('n', $date) == "12" && $weekOfYear == 1) {
                              // It's the first week of the next year.
                              return 53;
                          }
                          else {
                              // It's a "normal" week.
                              return $weekOfYear;
                          }
                      }
                      
                      //this function
                      function weekOfmonth(DateTime $date)
                      {
                        $dayFirstMonday = date_create('first monday of '.$date->format('F Y'))->format('j');
                        return (int)(($date->format('j') - $dayFirstMonday +7)/7) + ($dayFirstMonday == 1 ? 0 : 1);
                      }
                      
                      $dt = date_create('1900-01-01');
                      $end = date_create('2038-01-02');
                      $countOk = 0;
                      $countError = 0;
                      for(;$dt < $end; $dt->modify('+1 Day')){
                          $ts = $dt->getTimestamp();
                          if(weekOfmonth($dt) === weekOfMonthAnders($ts)){
                             ++$countOk; 
                          }
                          else {
                             ++$countError;
                          }
                      }
                      echo $countOk.' compare ok, '.$countError.' errors';
                      

                      结果:50405 比较正常,0 个错误

                      【讨论】:

                        【解决方案18】:

                        我采用了视觉方法(就像我们在现实世界中的做法一样)。我没有使用公式或其他什么,而是通过可视化文字日历然后将日期放入多维数组来解决它(或者至少我认为我做到了)。第一个维度对应于星期。

                        我希望有人可以检查它是否经得起您的测试。或者用不同的方法帮助别人。

                        # date in this format 2021-08-03
                        # week_start is either Sunday or Monday
                        function getWeekOfMonth($date, $week_start = "Sunday"){
                        
                            list($year, $month, $day) = explode("-", $date);
                        
                            $dates = array();
                            $current_week = 1;
                        
                            $new_week_signal = $week_start == "Sunday" ? 6 : 0;
                        
                            for($i = 1; $i <= date("t", strtotime($date)); $i++){
                                $current_date = strtotime("{$year}-{$month}-".$i);
                                $dates[$current_week][] = $i;
                                if(date('w', $current_date) == $new_week_signal){
                                    $current_week++;
                                }
                            }
                        
                            foreach($dates as $week => $days){
                                if(in_array(intval($day), $days)){
                                    return $week;
                               }
                            }
                        
                            return false;
                        
                        }
                        

                        【讨论】:

                        • 好主意,但似乎有点无效。每个月有 4 周,额外的天数不算作一周。例如,如果您检查“2021-12-27”,则使用您的解决方案,它将返回“5”,这不是有效的“周”。
                        • @Mecanik:是的,如果你这么说,你是对的。但就我和 OP 而言,第 5 周有效。
                        【解决方案19】:
                        //It's easy, no need to use php function
                        //Let's say your date is 2017-07-02
                        
                        $Date = explode("-","2017-07-02");
                        $DateNo = $Date[2];
                        $WeekNo = $DateNo / 7; // devide it with 7
                        if(is_float($WeekNo) == true)
                        {
                           $WeekNo = ceil($WeekNo); //So answer will be 1
                        }  
                        
                        //If value is not float then ,you got your answer directly
                        

                        【讨论】:

                        • 这仅在当月的第一天是星期一时给出正确的结果。
                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-12-18
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-08-06
                        相关资源
                        最近更新 更多