PHP计算两个日期之间相隔的周数

42

你好,如何找到两个日期之间的周数和每周一的日期。例如,从2009年10月7日到今天。

注意:考虑闰年和其他与日期相关的限制。


您的日期数据是以什么格式呈现的? - Sam Becker
1
实际上格式无所谓,因为它最终会被转换为 Unix 时间戳。 - Your Common Sense
10个回答

84

这里有一个使用DateTime的替代方案:-

function datediffInWeeks($date1, $date2)
{
    if($date1 > $date2) return datediffInWeeks($date2, $date1);
    $first = DateTime::createFromFormat('m/d/Y', $date1);
    $second = DateTime::createFromFormat('m/d/Y', $date2);
    return floor($first->diff($second)->days/7);
}

var_dump(datediffInWeeks('1/2/2013', '6/4/2013'));// 21

查看它的运行情况


2
我认为这个答案比被接受的答案更完整,特别是如果@Piskvor说datediff有漏洞的话。 - Hector Ordonez
1
这里的 floor($first->diff($second)->days/7) 给我带来了问题...所以这可能取决于你的程序是否需要将2.8周视为3周或2周。 - Aukhan
3
那你可以随意修改以适应你的需要 :) 在这里发布的代码片段不可能适用于所有情况,它们只是建议性的起点。也许 round() 函数更适合你? - vascowhite
@vascowhite ... 是的 :) 那天我修改了它以适应我的需求,我想通过 ceil() 来查看它。感谢你的片段!我认为它应该成为核心 PHP 的一部分...喜欢 moment.js 处理这些事情的方式 ;) - Aukhan

23
echo datediff('ww', '9 July 2003', '4 March 2004', false);

在以下网站中找到这个函数: http://www.addedbytes.com/code/php-datediff-function/

更新

链接已经失效(2017年9月),因此下面的函数来自于Web Archive:

<?php

/**
 * @param $interval
 * @param $datefrom
 * @param $dateto
 * @param bool $using_timestamps
 * @return false|float|int|string
 */
function datediff($interval, $datefrom, $dateto, $using_timestamps = false)
{
    /*
    $interval can be:
    yyyy - Number of full years
    q    - Number of full quarters
    m    - Number of full months
    y    - Difference between day numbers
           (eg 1st Jan 2004 is "1", the first day. 2nd Feb 2003 is "33". The datediff is "-32".)
    d    - Number of full days
    w    - Number of full weekdays
    ww   - Number of full weeks
    h    - Number of full hours
    n    - Number of full minutes
    s    - Number of full seconds (default)
    */

    if (!$using_timestamps) {
        $datefrom = strtotime($datefrom, 0);
        $dateto   = strtotime($dateto, 0);
    }

    $difference        = $dateto - $datefrom; // Difference in seconds
    $months_difference = 0;

    switch ($interval) {
        case 'yyyy': // Number of full years
            $years_difference = floor($difference / 31536000);
            if (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom), date("j", $datefrom), date("Y", $datefrom)+$years_difference) > $dateto) {
                $years_difference--;
            }

            if (mktime(date("H", $dateto), date("i", $dateto), date("s", $dateto), date("n", $dateto), date("j", $dateto), date("Y", $dateto)-($years_difference+1)) > $datefrom) {
                $years_difference++;
            }

            $datediff = $years_difference;
        break;

        case "q": // Number of full quarters
            $quarters_difference = floor($difference / 8035200);

            while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($quarters_difference*3), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
                $months_difference++;
            }

            $quarters_difference--;
            $datediff = $quarters_difference;
        break;

        case "m": // Number of full months
            $months_difference = floor($difference / 2678400);

            while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($months_difference), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
                $months_difference++;
            }

            $months_difference--;

            $datediff = $months_difference;
        break;

        case 'y': // Difference between day numbers
            $datediff = date("z", $dateto) - date("z", $datefrom);
        break;

        case "d": // Number of full days
            $datediff = floor($difference / 86400);
        break;

        case "w": // Number of full weekdays
            $days_difference  = floor($difference / 86400);
            $weeks_difference = floor($days_difference / 7); // Complete weeks
            $first_day        = date("w", $datefrom);
            $days_remainder   = floor($days_difference % 7);
            $odd_days         = $first_day + $days_remainder; // Do we have a Saturday or Sunday in the remainder?

            if ($odd_days > 7) { // Sunday
                $days_remainder--;
            }

            if ($odd_days > 6) { // Saturday
                $days_remainder--;
            }

            $datediff = ($weeks_difference * 5) + $days_remainder;
        break;

        case "ww": // Number of full weeks
            $datediff = floor($difference / 604800);
        break;

        case "h": // Number of full hours
            $datediff = floor($difference / 3600);
        break;

        case "n": // Number of full minutes
            $datediff = floor($difference / 60);
        break;

        default: // Number of full seconds (default)
            $datediff = $difference;
        break;
    }

    return $datediff;
}

3
许多时间范围都存在一个不太明显的 bug,包括 2012 年、2016 年、2020 年和 2024 年,这个 bug 就是二月份的 29 号。 - Piskvor left the building
4
如果链接失效的话,包含datediff函数的代码会很有用。 - AbcAeffchen
13
我到底是怎样在谷歌上搜索两个日期之间相差几周的函数,然后却在StackOverflow上看到一条评论,里面链接着我自己的网站和我已经写好解决这个问题的代码?我觉得我快疯了…… - Dave Child
@Piskvor 像这样的复杂函数,你应该拥有某种可重现代码来证明它的正确性。它运行得很好,我没有发现任何错误。 - raveren
@DaveChild发现了一个可以计算两个日期之间周数的函数,你看过吗? - Harry Bosh

23
$diff = strtotime($dateto, 0) - strtotime($datefrom, 0);
echo floor($diff / 604800);

1
存在夏令时问题。可能的解决方案:使用协调世界时(UTC)工作,使用 round 而非 floor,或者使用 DateTime::diff 而非减法运算。 - Brilliand
DST @Brilliand 是什么? - Radmation
1
@Radmation 夏令时 - Brilliand

3

这个做得很好


function weeks_between($datefrom, $dateto)
    {
        $datefrom = DateTime::createFromFormat('d/m/Y H:i:s',$datefrom);
        $dateto = DateTime::createFromFormat('d/m/Y H:i:s',$dateto);
        $interval = $datefrom->diff($dateto);
        $week_total = $interval->format('%a')/7;
        return floor($week_total);

    }

weeks_between("25/02/2000 11:30:00","05/06/2015 11:29:59")

2
以下函数计算两个时间戳之间的“口语周”(例如,如果您在星期六,则下周一是下一周)。

function days_between($datefrom,$dateto){
    $fromday_start = mktime(0,0,0,date("m",$datefrom),date("d",$datefrom),date("Y",$datefrom));
    $diff = $dateto - $datefrom;
    $days = intval( $diff / 86400 ); // 86400  / day

    if( ($datefrom - $fromday_start) + ($diff % 86400) > 86400 )
        $days++;

    return  $days;
}

function weeks_between($datefrom, $dateto)
{
    $day_of_week = date("w", $datefrom);
    $fromweek_start = $datefrom - ($day_of_week * 86400) - ($datefrom % 86400);
    $diff_days = days_between($datefrom, $dateto);
    $diff_weeks = intval($diff_days / 7);
    $seconds_left = ($diff_days % 7) * 86400;

    if( ($datefrom - $fromweek_start) + $seconds_left > 604800 )
        $diff_weeks ++;

    return $diff_weeks;
}

1
我更新了上面Tom的代码,使函数可以自动检测字符串或整数日期/时间。
<?php
/**
 * @param $interval
 * @param $datefrom
 * @param $dateto
 * @param bool $using_timestamps // Removed 08-29-2019 Jay Simons - Now auto-detects
 * @return false|float|int|string
 */
function datediff($interval, $datefrom, $dateto)
{
    /*
    $interval can be:
    yyyy - Number of full years
    q    - Number of full quarters
    m    - Number of full months
    y    - Difference between day numbers
           (eg 1st Jan 2004 is "1", the first day. 2nd Feb 2003 is "33". The datediff is "-32".)
    d    - Number of full days
    w    - Number of full weekdays
    ww   - Number of full weeks
    h    - Number of full hours
    n    - Number of full minutes
    s    - Number of full seconds (default)
    */
/*Remove
    if (!$using_timestamps) {
        $datefrom = strtotime($datefrom, 0);
        $dateto   = strtotime($dateto, 0);
    }
*/
    // Auto-detect string date or int date:
    $dateto_str = strtotime($dateto);
    $datefrom_str = strtotime($datefrom);
    if ($dateto_str) $dateto = $dateto_str;
    if ($datefrom_str) $datefrom = $datefrom_str;

    $difference        = $dateto - $datefrom; // Difference in seconds
    $months_difference = 0;

    switch ($interval) {
        case 'yyyy': // Number of full years
            $years_difference = floor($difference / 31536000);
            if (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom), date("j", $datefrom), date("Y", $datefrom)+$years_difference) > $dateto) {
                $years_difference--;
            }

            if (mktime(date("H", $dateto), date("i", $dateto), date("s", $dateto), date("n", $dateto), date("j", $dateto), date("Y", $dateto)-($years_difference+1)) > $datefrom) {
                $years_difference++;
            }

            $datediff = $years_difference;
        break;

        case "q": // Number of full quarters
            $quarters_difference = floor($difference / 8035200);

            while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($quarters_difference*3), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
                $months_difference++;
            }

            $quarters_difference--;
            $datediff = $quarters_difference;
        break;

        case "m": // Number of full months
            $months_difference = floor($difference / 2678400);

            while (mktime(date("H", $datefrom), date("i", $datefrom), date("s", $datefrom), date("n", $datefrom)+($months_difference), date("j", $dateto), date("Y", $datefrom)) < $dateto) {
                $months_difference++;
            }

            $months_difference--;

            $datediff = $months_difference;
        break;

        case 'y': // Difference between day numbers
            $datediff = date("z", $dateto) - date("z", $datefrom);
        break;

        case "d": // Number of full days
            $datediff = floor($difference / 86400);
        break;

        case "w": // Number of full weekdays
            $days_difference  = floor($difference / 86400);
            $weeks_difference = floor($days_difference / 7); // Complete weeks
            $first_day        = date("w", $datefrom);
            $days_remainder   = floor($days_difference % 7);
            $odd_days         = $first_day + $days_remainder; // Do we have a Saturday or Sunday in the remainder?

            if ($odd_days > 7) { // Sunday
                $days_remainder--;
            }

            if ($odd_days > 6) { // Saturday
                $days_remainder--;
            }

            $datediff = ($weeks_difference * 5) + $days_remainder;
        break;

        case "ww": // Number of full weeks
            $datediff = floor($difference / 604800);
        break;

        case "h": // Number of full hours
            $datediff = floor($difference / 3600);
        break;

        case "n": // Number of full minutes
            $datediff = floor($difference / 60);
        break;

        default: // Number of full seconds (default)
            $datediff = $difference;
        break;
    }

    return $datediff;
}
?>

0
    $formt_start_date = new DateTime($start_date);
    $formt_end_date = new DateTime($end_date);
    for ($i = $formt_start_date; $i < $formt_end_date; $i->modify('+7 day')) {
        $week_frequency[] = new DateTime($i->format("Y-m-d"));

    }

1
虽然这段代码可能解决了提问者的问题,但最好添加上下文或解释为什么这可以解决问题,以便未来的访问者可以从您的帖子中学习,并将此知识应用于自己的问题。高质量的答案更有可能被点赞,并为SO作为平台的价值和质量做出贡献。如果有帮助,您还可以添加文档链接。 - SherylHohman

0
    This will count a single day as one week and if you select sunday of one week and monday of another. though only 2 days are there but of different weeks therefore 2 weeks will be counted.


    Also works for different years


        function return_week($datee){
            $duedt = explode("-", $datee);
            $date  = mktime(0, 0, 0, $duedt[1], $duedt[2], $duedt[0]);
            $week  = (int)date('W', $date);
            return $week ;

        }

       function weeks_between($strtDate, $endDate){  
    // input dates of format yyyy-mm-dd between which you want to get number of weeks
    $start_date = DateTime::createFromFormat("Y-m-d", $strtDate);
    $end_date =  DateTime::createFromFormat("Y-m-d", $endDate);
    $start_year = $start_date->format("Y");
    $end_year = $end_date->format("Y");
    $start_month = $start_date->format("m");
    $end_month = $end_date->format("m");
    $week1  = return_week($strtDate);
    $week2  = return_week($endDate);
    $diff = $end_year - $start_year;;
    if($end_month<$start_month && $start_year!=$end_year ){
        $week_diff = (52*$diff-$week1)+$week2+1;
        return ($start_year==$end_year)?$week_diff:abs($week_diff);
    }else{
        $week_diff = $week2-$week1+1;
        return ($start_year==$end_year)?$week_diff:abs($week_diff)+52*$diff;
    }


    }

//call to function
weeks_between(""2018-10-21,"2019-10-21");

-1

PHP两个日期之间周数问题

以下是解决方案(根据https://stackoverflow.com/questions/27560850/php-number-of-week-between-2-dates-issue中提出的一个问题进行了修正),用于查找日期范围之间的周数。

由于下面的解决方案使用日期差异,为了包含起始日期所在的第一周,必须使用floor函数;为了包括结束日期所在的周数,必须使用ceil函数,才能返回正确的周数。

$strtDate = '2014-01-01';
$endDate = '2015-03-17';

$startDateWeekCnt = round(floor( date('d',strtotime($strtDate)) / 7)) ;
// echo $startDateWeekCnt ."\n";
$endDateWeekCnt = round(ceil( date('d',strtotime($endDate)) / 7)) ;
//echo $endDateWeekCnt. "\n";

$datediff = strtotime(date('Y-m',strtotime($endDate))."-01") - strtotime(date('Y-m',strtotime($strtDate))."-01");
$totalnoOfWeek = round(floor($datediff/(60*60*24)) / 7) + $endDateWeekCnt - $startDateWeekCnt ;
echo $totalnoOfWeek ."\n";

-1

点击此处查看完整代码

在PHP中获取两个日期之间的所有周数

getNoOfWeek()将返回带有年份的周编号数组。您可以通过week_text_alter()更改此数组的格式。

function getNoOfWeek($startDate, $endDate){
  // convert date in valid format
  $startDate = date("Y-m-d", strtotime($startDate));
  $endDate = date("Y-m-d", strtotime($endDate));
  $yearEndDay = 31;
  $weekArr = array();
  $startYear = date("Y", strtotime($startDate));
  $endYear = date("Y", strtotime($endDate));

  if($startYear != $endYear) {
    $newStartDate = $startDate;

    for($i = $startYear; $i <= $endYear; $i++) {
      if($endYear == $i) {
        $newEndDate = $endDate;
      } else {
        $newEndDate = $i."-12-".$yearEndDay;
      }
      $startWeek = date("W", strtotime($newStartDate));
      $endWeek = date("W", strtotime($newEndDate));
      if($endWeek == 1){
        $endWeek = date("W", strtotime($i."-12-".($yearEndDay-7)));
      }
      $tempWeekArr = range($startWeek, $endWeek);
      array_walk($tempWeekArr, "week_text_alter", 
         array('pre' => 'Week ', 'post' => " '". substr($i, 2, 2) ));
      $weekArr = array_merge($weekArr, $tempWeekArr);

      $newStartDate = date("Y-m-d", strtotime($newEndDate . "+1 days"));
    }
  } else {
    $startWeek = date("W", strtotime($startDate));
    $endWeek = date("W", strtotime($endDate));
    $endWeekMonth = date("m", strtotime($endDate));
    if($endWeek == 1 && $endWeekMonth == 12){
      $endWeek = date("W", strtotime($endYear."-12-".($yearEndDay-7)));
    }
    $weekArr = range($startWeek, $endWeek);
    array_walk($weekArr, "week_text_alter", 
       array('pre' => 'Week ', 'post' => " '". substr($startYear, 2, 2)));
  }
  $weekArr = array_fill_keys($weekArr, 0);
  return $weekArr;
}

function week_text_alter(&$item1, $key, $prefix)
{
  $item1 = $prefix['pre']. $item1 . $prefix['post'];
}


Output 1 -
$weekArr = getNoOfWeek('2014-01-01', '2014-02-10');

Array
(
    [Week 1 '14] => 0
    [Week 2 '14] => 0
    [Week 3 '14] => 0
    [Week 4 '14] => 0
    [Week 5 '14] => 0
    [Week 6 '14] => 0
    [Week 7 '14] => 0
)

Output 2 -
$weekArr = getNoOfWeek('2013-12-01', '2014-02-10');

Array
(
    [Week 48 '13] => 0
    [Week 49 '13] => 0
    [Week 50 '13] => 0
    [Week 51 '13] => 0
    [Week 52 '13] => 0
    [Week 1 '14] => 0
    [Week 2 '14] => 0
    [Week 3 '14] => 0
    [Week 4 '14] => 0
    [Week 5 '14] => 0
    [Week 6 '14] => 0
    [Week 7 '14] => 0
)

希望这能对你有所帮助。

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