在PHP中如何从日期获取月份中的周数?

20

我有一个随机日期的数组(不是来自MySQL)。我需要按周分组,从第一周开始到第五周为止,分别命名为Week1、Week2等。

我现在拥有的是:

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

请澄清您的问题。 - William Smith
20个回答

38

我认为这个关系应该是真实的,并且会派上用场:

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", ...)


当1月份在前一年的12月31日并结束时,这个程序可能无法正常运行。 - CiprianIonescu
@CiprianIonescu 谢谢您指出这一点。确实,例如2021-01-18会给出错误的答案。我已添加了一个通知,并将尝试稍后更新回答以进行修复。再次感谢! - Anders
返回了几年末数据的错误结果:2018-12-31出错,No=-46,期望值为6;2019-12-30出错,No=-46,期望值为6;2019-12-31出错,No=-46,期望值为6;2024-12-30出错,No=-46,期望值为6;2024-12-31出错,No=-46,期望值为6;2025-12-29出错,No=-47,期望值为5;2025-12-30出错,No=-47,期望值为5;2025-12-31出错,No=-47,期望值为5。 - jspit
1
我认为现在这个可以了。感谢您的纠正。我现在得到的结果与我的函数一样,覆盖了1970年至2038年所有日期。 - jspit
@jspit 太好了!我可能让一些复制粘贴者在他们的代码中引入了奇怪的错误。你阻止了这种情况,我很感激。 :-) - Anders
显示剩余3条评论

14
你可以使用下面的函数,完全注释了:
/**
 * Returns the number of week in a month for the specified date.
 *
 * @param string $date (can be in YYYY-MM-DD, DD-MM-YYYY or MM/DD/YYYY format)
 * @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;
}

然后像这样使用它
$weekOfTheMonth = weekOfMonth("2023-10-19");
echo $weekOfTheMonth; // should print 3

这也没有给出正确的结果... '2015-09-06' 应该是第二周而不是第一周。 - Asif Hussain
1
我认为将 $i = 1; $i <= $d; ++$i 改成 $i = 1; $i < $d; ++$i 可以得到完美的结果。 - Jazuly
你为什么这样建议?有特定的情况失败了吗? - Matteo Tassinari
我认为@Asif的建议是正确的。我之前使用的公式出现了问题,有些日期显示的周数超过了6,而这在2021-10-31和2022-01-31这几个日期中从未出现过,因为最大周数只有6。 - swapnil akolkar
@Augusto 我不认为在这个网站上给别人的答案添加代码是合适的,不过我会接受它。 - undefined
显示剩余3条评论

10

正确的方式是

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

https://dev59.com/KlwY5IYBdhLWcg3wcXeE#37753387 - j4r3k

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? - vidhi
如果我写了 echo weekOfMonth('2017-10-01'); 它会输出 2。我认为它应该是 1。 - vidhi

3
function getWeekOfMonth(DateTime $date) {
    $firstDayOfMonth = new DateTime($date->format('Y-m-1'));

    return ceil(($firstDayOfMonth->format('N') + $date->format('j') - 1) / 7);
}

Goendg解决方案在2016-10-31失效了。


2
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') // returns 3


3
欢迎来到 Stack Overflow!请不要只是把你的源代码扔在这里。友好地尝试给你的答案一个好的描述,这样其他人会喜欢它并点赞它。详情请见:如何撰写优秀答案? - sɐunıɔןɐqɐp
这个未解释的答案并没有像被接受的答案那样在2023-10-20返回4 - undefined

1
你也可以使用这个简单的公式来找到月份的周数。
$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

这个答案显示2023-10-203,但是被接受的答案给出的是4 - undefined

1

根据月份中第一个星期的时间_t wday (0代表星期日,6代表星期六)的firstWday,此函数返回该月份内以星期日为基准的周数:

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

这个答案显示2023-10-203,但是被接受的答案给出的是4 - undefined
1
第一个被接受的答案给出的结果是4,但是这是基于以星期一为基准的周计算;原始问题要求基于以星期日为基准的周计算。被接受的答案确实有一个注释,指示如果你想要基于以星期日为基准的周计算,应该如何修改。如果你进行了这个修改,那么结果将变为3。这是正确的值;对于以星期日为起始的本周日期来说,这是正确的。 - undefined

1
$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);

正常工作。

当涉及到夏令时的时候,利用86400的技术往往容易出现问题。这个答案缺少了相关的教育性解释。 - undefined

1

我的函数。主要思想:我们将计算从本月第一天到当前日期经过的周数。当前周数将是下一个周数。遵循规则:“一周从星期一开始”(对于基于星期日的类型,我们需要转换增加算法)。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接