質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

phpで「第2月曜」など特定の日にちを取得したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,047

taiyo-2017

score 43

php、cakePHP3を使用して、「第2月曜」などの日にちを取得したいと思っています。

https://php-archive.net/php/n-week/
こちらのサイトを見て、日にちを取得できることが分かったのですが、
特定の1日だけでなく、範囲の中で該当する日にち全てを取得する場合に有効なロジック?や関数などはありますでしょうか?
アドバイス等いただければと思います。

例)期間:2018年1月1日~2050年7月25日 第2、第3火曜、木曜

今考えている方法

$fromY = 2018;
$fromM = 1;
$fromD = 1;

$toY = 2050;
$toM = 7;
$toD = 25;

$week_array = [2, 3]; // 2週、3週
$week_of_day_array = [2, 4]; // 火曜、木曜

$dates = []; // 期間中の日にちを入れる配列

for ($year = $fromY ; $year <= $toY; $year++) {
  for ($month = 1 ; $month <=12 ; $month++) {
    if ($year == $fromY && $month < $fromM) { continue; }
    if ($year == $toY && $month > $toM) { break; }

    $datetime = new DateTime();
    $datetime->setTimezone( new DateTimeZone('Asia/Tokyo') );

    //その月の始まりは何曜日か
    $datetime->setDate($year, $month, 1);
    $w = (int)$datetime->format('w');

  foreach ($week_of_day_array as $wday) {
      //指定された曜日の最初の日
      $first = ($wday - $w >= 0) ? 1 + $wday - $w : 1 + $wday - $w + 7;

      foreach ($week_array as $week) {
        //日にちを算出
        $day  = $first + ( 7 * ($week - 1) );
        $datetime->setDate($year, $month, $day);

        $dates[] = $datetime->format('Y-m-d'); // 日にち格納
      }
    }
  }
}

追記

期間や曜日、週などは不定となっているので
・期間:2018年1月1日~2050年7月25日 第1、第3火曜、木曜、
・期間:2018年1月31日~2019年12月25日 第5木曜、
・期間:2018年1月1日~2019年1月1日 第3日曜、月曜
など、多くのものに対応できるようにしたいと考えています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

こんな感じですかね

<?PHP
$start="2018-01-01";
$end  ="2050-07-25";

$d_start =strtotime($start." first day of 0 month");
$d_end   =strtotime($end." first day of 1 month");

$list=[];
$d=$d_start;
while($d<$d_end){
  $list[]=date("Y-m-d",strtotime(date("Y-m-d",$d)." first tuesday  of 0 month +1 week"));
  $list[]=date("Y-m-d",strtotime(date("Y-m-d",$d)." first tuesday  of 0 month +3 week"));
  $list[]=date("Y-m-d",strtotime(date("Y-m-d",$d)." first thursday of 0 month +1 week"));
  $list[]=date("Y-m-d",strtotime(date("Y-m-d",$d)." first thursday of 0 month +3 week"));
  $d=strtotime(date("Y-m-d",$d)." + 1 month");
}
sort($list);
$list=array_filter($list,function($x) use($start,$end){
  return $x>=$start and  $x<=$end;
});
print_r($list);

追記

任意の曜日とn番目を指定

$start="2018-01-01";
$end  ="2050-07-25";

$d_start =strtotime($start." first day of 0 month");
$d_end   =strtotime($end." first day of 1 month");

$target=[["monday",1],["tuesday",2],["thursday",3]];
//上記、第1月曜、第2火曜、第3木曜

$list=[];
$d=$d_start;
$c=0;
while($d<$d_end){
  foreach($target as $val){
    $list[]=date("Y-m-d",strtotime(date("Y-m-d",$d).sprintf(" first %s of 0 month +%d week",$val[0],$val[1]-1)));
  }

  $d=strtotime(date("Y-m-d",$d)." + 1 month");
}
sort($list);
$list=array_filter($list,function($x) use($start,$end){
  return $x>=$start and  $x<=$end;
});
print_r($list);

第n週のx曜日

$start="2019-01-01";
$end  ="2019-12-31";
$d_start =strtotime($start." first day of 0 month");
$d_end   =strtotime($end." first day of 1 month");
$day_of_week=["sunday","monday","tueday","wednesday","thuesday","friday","saturday"];
$target=[["sunday",6]];
$list=[];
$d=$d_start;
$c=0;
while($d<$d_end){
  $w=(date("w",$d));
  foreach($target as $val){
    $offset=array_search($val[0],$day_of_week)<$w?1:0;
    $day=date("Y-m-d",strtotime(date("Y-m-d",$d).sprintf(" first %s of 0 month +%d week",$val[0],$val[1]-1-$offset)));
    if(date("Y-m",$d)==substr($day,0,7)) $list[]=$day;
  }
  $d=strtotime(date("Y-m-d",$d)." + 1 month");
}
sort($list);
$list=array_filter($list,function($x) use($start,$end){
  return $x>=$start and  $x<=$end;
});
print_r($list);


上記で

$start="2018-01-01";
$end  ="2050-07-25";
$target=[["monday",1],["tuesday",2],["thursday",3]];


とすれば最初の命題にも合致すると思います

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/27 09:44

    その場合は日付は取得せず「null」の扱いをしたいです。

    キャンセル

  • 2019/05/27 10:20

    上記offset処理をいれました

    キャンセル

  • 2019/05/27 11:34

    日を取得することができました!
    改めて、コードを順に追って理解していきたいと思います。
    丁寧にありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る