2013-04-08 36 views
5

与えられた2つの日付間のすべての日曜日を計算したいと思います。私は次のコードを試しました。日数が少なくても、より多くの日数を入力すれば正常に動作します。それは処理を続け、最大実行時間は私が時間を変更したが、実行時間も200秒であっても処理を続けます。2つの日付間の日曜日を計算する

コードは、助けてください

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

?> 

です。

+0

は、あなたがそのような日付文字列にforループを使用することはできますか? – andrewsi

+0

そのような文字列をインクリメントすることはできません。どのように他の人がそれを見てください:http://stackoverflow.com/search?q=php+number+of+sundays –

+0

これは[projectユーラー問題(19)]ですか?(http://projecteuler.net/problem=19 )? – HamZa

答えて

25

ジョン・コンデの答えは正しいですが、ここでは、より効率的かつMathyさんのソリューションです:

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

まず、強力なビルトインされているPHPオブジェクト一部DateTimeのオブジェクトは、問題のまさにこの種のもので作成します。

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

次に、(2番目のパラメータは、この値は常にポジティブであることを保証し、ここでtrueを渡す)$startから$endに違いを見つけるためにDateTime::diffを使用し、それらの間の日数を取得します。

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

ここは大きなものですが、それほど複雑ではありません。まず、毎週1つの日曜日があることを知っています。したがって、intvalで最も近いintに切り捨てられて、少なくとも$days/7日曜日があります。

これに加えて、1週間未満の日曜日があります。たとえば、次週の金曜日から月曜日には4日間が含まれます。それらの1つは日曜日です。それで、私たちがいつ始まり、終わるかによって、別のものが存在する可能性があります。これが占めるのは簡単である:(DateTime::formatを参照)

  • $start->format('N')は1から7までの数で開始日、(1は月曜日で、7は日曜日)のために私たちに週のISO-8601日を与えます。
  • $days % 7は、週に均等に分割されない残存期間の日数を示します。

開始日と残存日数が合計して7以上になると、日曜日に届きました。そのことを知っているならば、その式を追加するだけでよいのですが、それが真の場合は1、偽ならば0、それはintの値に加算されるためです。

あなたはそれを持っています!この方法の利点は、与えられた時間の間に毎日繰り返し実行する必要がなく、日曜日かどうかを確認する必要がないため、計算量が大幅に節約され、見た目も本当に賢くなります。希望が助けてくれる!

+2

この部分は真ではありません。$ daysと7は両方ともint値なので、これは常に最も近いintに切り捨てられます。それを丸めるには、[floor()](http://www.php.net/manual/en/function.floor.php)のようなラウンド関数を使用する必要があります。 '$ end = new DateTime( '2013-02-20');'と出力は小数です。 – HamZa

+2

あなたは絶対に正しいですよ!私はPHPについて少し話していたことを忘れていました。 –

+1

+1を賢明な方法で説明し、詳細に説明します。 –

8
<?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

+0

ありがとうございます。できます。それで文字列が正しくインクリメントされなかったので動作しませんでしたか? –

+0

基本的にはyesです。文字列、特に日付を使って作業することは、そのために設計された機能に任せておくことをお勧めします。 DateTimeは、日付を扱うように特別に設計されています。 –

+0

はいそうです。ありがとう。 –

0

日曜日を特定の日付範囲にしたい場合は、これが解決策です。

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 
関連する問題