【问题标题】:calculate sundays between two dates计算两个日期之间的星期日
【发布时间】:2013-03-30 22:50:54
【问题描述】:

我想计算给定两个日期之间的所有星期日。我尝试了以下代码。如果天数较少但如果我输入更多天数,它工作正常。它继续处理并且最大执行时间超过了我更改的时间,但它甚至继续处理,即使执行时间为 200 秒。

代码是

<?php
$one="2013-01-01";
$two="2013-02-30";

$no=0;
for($i=$one;$i<=$two;$i++)
{

    $day=date("N",strtotime($i));
    if($day==7)
    {
    $no++;
    }
}
echo $no;

?>

请帮忙。

【问题讨论】:

标签: php time


【解决方案1】:
<?php
$no = 0;
$start = new DateTime('2013-01-01');
$end   = new DateTime('2013-04-30');
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt)
{
    if ($dt->format('N') == 7)
    {
        $no++;
    }
}
echo $no;

See it in action

【讨论】:

  • 谢谢。有用。所以它不起作用,因为字符串没有正确增加?
  • 基本上是的。处理字符串,尤其是日期,最好留给专门设计的功能。 DateTime 是专门为处理日期而设计的,正如您所见,它很容易做到。
  • @John 演示链接已失效。
【解决方案2】:

John Conde 的回答是正确的,但这里有一个更高效、更数学的解决方案:

$start = new DateTime('2013-01-06');
$end = new DateTime('2013-01-20');
$days = $start->diff($end, true)->days;

$sundays = intval($days / 7) + ($start->format('N') + $days % 7 >= 7);

echo $sundays;

让我为你分解一下。

$start = new DateTime('2013-01-06');
$end = new DateTime('2013-01-20');

首先,创建一些 DateTime 对象,它们是强大的内置 PHP 对象,专门用于解决此类问题。

$days = $start->diff($end, true)->days;

接下来,使用DateTime::diff$start$end之间的差异(此处将true作为第二个参数传递可确保该值始终为正),并获取它们之间的天数。

$sundays = intval($days / 7) + ($start->format('N') + $days % 7 >= 7);

这是一个大问题 - 但它并没有那么复杂,真的。首先,我们知道每个星期都有一个星期日,所以我们至少有 $days / 7 星期日作为开始,四舍五入到最接近的 intintval

除此之外,在不到一周的时间内可能会有一个星期日;例如,周五到下周的周一包含 4 天;其中之一是星期天。所以,取决于我们何时开始和结束,可能会有另一个。这很容易解释:

  • $start-&gt;format('N')(请参阅DateTime::format)为我们提供ISO-8601一周中的开始日期,这是一个从 1 到 7 的数字(1 是星期一,7 是星期日)。
  • $days % 7 为我们提供了未平均划分为周的剩余天数。

如果我们的开始日期和剩余天数加起来达到 7 天或更多,那么我们就到了星期天。知道了这一点,我们只需要添加那个表达式,如果它是真的,它会给我们1,如果它是假的,它会给我们0,因为我们将它添加到int 值。

你有它!这种方法的优点是它不需要在给定时间之间每天迭代并检查是否是星期天,这将为您节省大量计算量,而且它会让您看起来非常聪明。希望对您有所帮助!

【讨论】:

  • 这部分不是真的Since $days and 7 are both int values, this will always be rounded down to the nearest int。你必须使用像floor()这样的舍入函数来舍入它,PHP不会为你做,例如$end = new DateTime('2013-02-20');,输出将是十进制的。
  • 你说得对,哎呀!忘了我说的是 PHP。
  • @QuinnStrahl 如果想找到任何一天的第一次出现(比如说星期天),那么如何找到呢?
  • @Er.KT 该算法适用于除最后一部分之外的任何一天:If our starting day and the number of leftover days add up to 7 or more, then we reached a Sunday. 您只需将此表达式:$start-&gt;format('N') + $days % 7 &gt;= 7 更改为类似$start-&gt;format('N') + $days % 7 &gt;= $ISO8601NumberForDesiredDayOfWeek 的内容。如上所述,一周中某一天的 ISO-8601 编号是介于 1 和 7 之间的数字,其中星期一为 1,星期日为 7。
  • 嗨,感谢您的解决方案。如果我想知道有多少个星期一,您能不能让它动态化。
【解决方案3】:

如果您希望星期天在特定日期范围内,这是一个解决方案。

function dateRange($begin, $end, $interval = null)
{
  $begin = new DateTime($begin);
  $end = new DateTime($end);

  $end = $end->modify('+1 day');
  $interval = new DateInterval($interval ? $interval : 'P1D');

  return iterator_to_array(new DatePeriod($begin, $interval, $end));
}

/* define date range */
$dates = dateRange('2018-03-01', '2018-03-31');

/* define weekdays */
$weekends = array_filter($dates, function ($date) {
  $day = $date->format("N");
  return $day === '6' || $day === '7';
});

/* weekdays output */
foreach ($weekends as $date) {
  echo $date->format("D Y-m-d") . "</br>";
}

/* define sundays */
$sundays = array_filter($dates, function ($date) {
  return $date->format("N") === '7';
});

/* sundays output */
foreach ($sundays as $date) {
echo $date->format("D Y-m-d") . "</br>";
}

/* define mondays */
$mondays = array_filter($dates, function ($date) {
 return $date->format("N") === '1';
});

/* mondays output */
foreach ($mondays as $date) {
echo $date->format("D Y-m-d") . "</br>";
}

只需在输出中更改您想要的任何天数:

Monday = 1
Tuesday = 2
Wednesday = 3
Thursday = 4
Friday = 5
Saturday = 6
Sunday = 7

【讨论】:

    猜你喜欢
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-25
    相关资源
    最近更新 更多