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

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

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

5回答

9973閲覧

PHPで、平日のみをカウントするプログラムで困っています

yoyoyoyogi

総合スコア47

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2015/10/16 08:13

編集2015/10/17 02:04

PHP初心者です。

PHPで平日だけをカウントアップする関数を作ったのですが、スタートが土日の時の計算が1日ずれてしまいます。

スタートした日の翌日から平日だけカウントするプログラムで、現在スタートが月曜から金曜なら狙ったカウントをしてくれてます。
月曜にスタートで5営業日後なら翌週の月曜日が返り値といった計算です(本当は曜日ではなくて日付です)。
スタート当日はカウントに含まず翌営業からのカウントな点がプログラムを複雑化してまして…

今のプログラムだと、スタートが土日祝日だと月曜日から1日目のカウントをしてしまって正解より1日少なくカウントされてしまいます。
土日にスタートする場合には、月曜スタート、祝日がある場合には祝日明けがスタートにしたいのですが苦戦しています。

以下書いているコードになります。
アドバイス頂けると嬉しいです、よろしくお願いします。

質問が不明瞭だったようで修正いたしました。

この既存コードに、スタートが土日祝日の場合に休日明けがスタートになるようなコードを追加したいのですがアイデアある方御教授頂けるとありがたいです。


スタートの日付
本日10月17日土曜にアクセス
10月19日月曜と処理したい

今のプログラムだと
3営業後は
21日水曜日になってしまいますが、狙っている結果は22日木曜日です。

function getNextBusinessDay($date_start, $count) { //祝日を手作業で配列にしています $holiday = array( "2015-09-21" => "敬老の日" , "2015-09-22" => "国民の休日", "2015-09-23" => "秋分の日", "2015-10-12" => "体育の日", "2015-11-3" => "文化の日", "2015-11-23" => "勤労感謝の日", "2015-12-23" => "天皇誕生日", );//祝日など納期除外の日付を連想配列で入力 $date = clone $date_start; $oneday = new DateInterval("P1D"); while ($count > 0) { $date->add($oneday); $str = $date->format("Y-m-d"); $w = $date->format("w"); if ($w < 1 #日曜 || $w > 5 #土曜 || isset($holiday[$str])) { #祝日 continue; } $count--; } return $date; } $order_time = new DateTime(); $order_time = $order_time->format('Hi'); $date = new DateTime(); コード

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/10/16 08:48

何がしたいのかイマイチ読み取れませんので、確認です。 たとえば、本日(2015年10月16日 金曜日)を基準にすると、次の営業日は2015年10月19日(月曜日)ですね。この場合に、どんな結果を返す関数を作りたいのですか?
yoyoyoyogi

2015/10/16 08:57

わかりにくくて申し訳ありません。 次の営業日はおっしゃる通り、19日月曜です。 関数の引数$countに渡す値が「何営業日後」と言う値になるのですが、6を渡したら、19日から数えて6営業日後の27日が返ってくるようにしたいです。
退会済みユーザー

退会済みユーザー

2015/10/16 09:02

なるほど。翌営業日だけではなく、○営業日後が何日なのかを返す関数を作りたいということですね。では、このように関数を作りたいのだということを明確に、質問文を編集してください。補足部分は見ない人も多いので。(見逃しやすい)
退会済みユーザー

退会済みユーザー

2015/10/16 09:46

6営業日後だと26日だはありませんか?
guest

回答5

0

シンプルに考えてみてはどうでしょうか
土日祝だったら1日ほしい仕様より足りない
ならば
土日祝だったら最初のカウントに+1してしまえばいい

その際に平日かどうか的な関数を作ってしまえば見た目的にもスマートです。
コードはPHPっぽい擬似コードです

PHP

1if(!is_平日かどうか){ 2 //平日じゃなかったら 3 $count++; 4} 5 6while($count > 0){ 7 8 if(is_平日かどうか){ 9 // 平日なら 10 $count--; 11 }else{ 12 //土日祝なら 13 continue; 14 } 15 16} 17 18fuction is_平日かどうか($date) { 19 return (boolean) 平日かどうか; 20}

ただ、それ以外に一点この仕様だと気になるところがあって、
祝日の日付を配列に定義しておく
だと、ハッピーマンデーの対応はどうするのか
と思う次第です。

投稿2015/10/20 04:32

編集2015/10/20 04:34
Nikumo

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんな感じでいかがでしょうか?

ポイントは

  • 起算日を"次の平日"にしてから日数の加算を実行する。(3行目)
  • 1日加算するたびに、平日でなければ"次の平日"まで移動させる。(8行目)

です。

ただし、日数の減算($count < 0の場合)は考慮していません。

また、祝日リスト ($public_holiday) をメンテナンスし続けるのは大変なので、
Kosuke_Shibuya様の回答のように、ご使用の環境が許すなら、ライブラリの導入を検討されてはいかがでしょうか?

php

1function getNextBusinessDay($date_start, $count) 2{ 3 $date = toNextWeekday($date_start); 4 5 for ($i = 0; $i < $count; $i++) 6 { 7 $date = $date->add(new DateInterval('P1D')); 8 $date = toNextWeekday($date); 9 } 10 11 return $date; 12} 13 14/** 15 * 引数で指定した日付が平日なら同じ日付を、平日でなければ"次の平日"を返却する。 16 */ 17function toNextWeekday($date) 18{ 19//祝日を手作業で配列にしています 20 $public_holiday = array( "2015-09-21", // 敬老の日 21 "2015-09-22", // 国民の休日 22 "2015-09-23", // 秋分の日 23 "2015-10-12", // 体育の日 24 "2015-11-03", // 文化の日 25 "2015-11-23", // 勤労感謝の日 26 "2015-12-23", // 天皇誕生日 27 );//祝日など納期除外の日付を連想配列で入力 28 29 $holiday = array(0, 6); // 0:日曜, 6:土曜 30 31 $date = clone $date; 32 33 while (in_array($date->format('Y-m-d'), $public_holiday) 34 || in_array($date->format('w'), $holiday)) 35 { 36 $date = $date->add(new DateInterval('P1D')); 37 } 38 39 return $date; 40} 41 42$today = new DateTime('2015-10-17'); 43print getNextBusinessDay($today, 0)->format('Y-m-d') . "\n"; 44print getNextBusinessDay($today, 1)->format('Y-m-d') . "\n"; 45print getNextBusinessDay($today, 2)->format('Y-m-d') . "\n"; 46print getNextBusinessDay($today, 10)->format('Y-m-d') . "\n"; 47print getNextBusinessDay(new DateTime('2015-12-22'), 1)->format('Y-m-d') . "\n";

実行結果

2015-10-19 2015-10-20 2015-10-21 2015-11-02 2015-12-24

投稿2015/10/17 10:57

編集2015/10/17 11:01
KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/10/17 11:15

元のコードを生かしつつ、可読性も良くていいコードですね。
KiyoshiMotoki

2015/10/17 12:35

Kosuke_Shibuya様、ありがとうございます。
guest

0

PHPで平日だけをカウントアップする
スタートした日の翌日から平日だけカウントする
土日にスタートする場合には、月曜スタート、祝日がある場合には祝日明けがスタート

3行目だけが何故そのようにしたいのか不明です。
営業日という表現だと変ですし、24時間まるまる作業できる日数というわけでもないんですね。
仕様をもう一度見直したほうが良いとは思いますけど…

しかし、何はともあれそのようなルールで動作する関数にしたいならば
ループ開始の前にスタート日をチェックして、土日祝日ならcountに1を加算すれば解決すると思います。

投稿2015/10/17 10:47

hirohiro

総合スコア2068

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

祝日・振替休日を取得するには、メンテナンスも楽なので、 PEAR::Date_Holidays_Japan にお任せする。

インストールは以下のコマンドで。

sh

1# pear install Date_Holidays_Japan-alpha

Calendar クラス(Calendar.class.php)の実装は以下のように。

php

1<?php 2 3/** 4 * カレンダークラス 5 * Calendar.class.php 6 */ 7final class Calendar 8{ 9 10 /** 11 * 日曜日 12 */ 13 const T_SUNDAY = 0; 14 15 /** 16 * 月曜日 17 */ 18 const T_MONDAY = 1; 19 20 /** 21 * 火曜日 22 */ 23 const T_TUESDAY = 2; 24 25 /** 26 * 水曜日 27 */ 28 const T_WEDNESDAY = 3; 29 30 /** 31 * 木曜日 32 */ 33 const T_THURSDAY = 4; 34 35 /** 36 * 金曜日 37 */ 38 const T_FRIDAY = 5; 39 40 /** 41 * 土曜日 42 */ 43 const T_SATURDAY = 6; 44 45 /** 46 * キャッシュに使用する祝日配列 47 * @var array(YYYY => array('YYYY-mm-dd' => '祝日名')) 48 */ 49 static private $_arrHolidays = array(); 50 51 /** 52 * 祝日を取得する 53 * @param integer $year 54 * @return array 55 */ 56 private static function getHolidays($year) 57 { 58 // 取得済みならキャッシュを使う 59 if (isset(static::$_arrHolidays[$year])) { 60 return static::$_arrHolidays[$year]; 61 } 62 63 // 未取得のとき 64 $errorLevel = error_reporting(); // エラー出力レベルを取得 65 error_reporting(E_NOTICE); // PHP Deprecated: Non-static method... を抑止 66 67 require_once 'Date/Holidays.php'; 68 $dh = Date_Holidays::factory('Japan', $year, 'ja_JP'); 69 $holidays = array(); 70 foreach ($dh->getHolidays() as $h) { 71 $holidays[$h->getDate()->format('%Y-%m-%d')] = $h->getTitle(); 72 } 73 error_reporting($errorLevel); // エラー出力レベルを戻す 74 75 ksort($holidays); 76 77 static::$_arrHolidays[$year] = $holidays; 78 return static::$_arrHolidays[$year]; 79 } 80 81 /** 82 * 祝日かどうかを判定する 83 * @param \DateTime $objDate 判定する日付 84 * @return bool 祝日ならtrue 85 */ 86 public static function isHoliday(\DateTime $objDate) 87 { 88 $year = $objDate->format('Y'); 89 $holidays = self::getHolidays($year); 90 return array_key_exists($objDate->format('Y-m-d'), $holidays); 91 } 92 93 /** 94 * 定休日かどうかを判定する 95 * @param \DateTime $objDate 判定する日付 96 * @return bool 定休日ならtrue 97 */ 98 public static function isRegularHoliday(\DateTime $objDate) 99 { 100 //定休日リスト 101 $arrRegularHoliday = array( 102 self::T_SUNDAY 103 , self::T_SATURDAY 104 ); 105 return in_array($objDate->format('w'), $arrRegularHoliday); 106 } 107 108 /** 109 * ○日後の営業日を取得する 110 * @param integer $dateAfter 指定しない時は翌営業日を返す 111 * @param \Datetime $objDate 基準日 112 * @return \Datetime 113 */ 114 public static function getWeekdayAfter($dateAfter = 1, \DateTime $objDate = null) 115 { 116 $date = (is_null($objDate)) ? new \DateTime() : $objDate; 117 $interval = new \DateInterval("P1D"); 118 for ($i = 0; $i < $dateAfter; $i++) { 119 $date->add($interval); 120 121 // 定休日・祝日のときはカウントしないので、$dateAfterをインクリメント 122 if (self::isRegularHoliday($date) || self::isHoliday($date)) { 123 $dateAfter++; 124 } 125 } 126 return $date; 127 } 128 129} 130

利用する時はこんな感じ。

php

1<?php 2 3require 'Calendar.class.php'; 4 5// usage 6// 2015-10-10(Friday) -> 2015-10-12(Monday) 体育の日 7$res = Calendar::getWeekdayAfter(1, new \DateTime('2015-10-10')); 8var_dump($res); // 2015-10-13 9 10// 2015-05-01(金) 11// 2015-05-02(土) 12// 2015-05-03(日・憲法記念日) 13// 2015-05-04(みどりの日) 14// 2015-05-05(こどもの日) 15// 2015-05-06(振替休日) 16$res = Calendar::getWeekdayAfter(1, new \DateTime('2015-05-01')); 17var_dump($res); // 2015-05-07


スタートの日付
本日10月17日土曜にアクセス
10月19日月曜と処理したい

今のプログラムだと
3営業後は
21日水曜日になってしまいますが、狙っている結果は22日木曜日です。

この条件おかしいのでは???

10/17(土)基準日
10/18(日)
10/19(月)1営業日後 - 引数には1を渡す(または未指定のときは暗黙的に翌営業日として扱う)
10/20(火)2営業日後 - 引数には2を渡す
10/21(水)3営業日後 - 引数には3を渡す
10/22(木)4営業日後 - 引数には4を渡す

このように考えたほうが、利用場面で自然だと思いますが…

投稿2015/10/16 13:07

編集2015/10/17 06:49
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

具体的なコードがあるので、ここをこう直せば良いと書いてあげれば喜ぶとは思うのですが
初心者と書かれていたので後々のためのことを考えてアドバイスに留めておきます。
以下のサイトで同様のことを時系列で、解説しています。
少し長いですが、全てを読んだ頃には理解出来ているのではないかと思います。
http://giraffe.topaz.ne.jp/wiki/doku.php/py:lesson12

投稿2015/10/16 08:52

YasuhiroMiyake

総合スコア1336

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問