はもちくわ

コードについて自分なりの解釈を書いてます。

【EXCEL】関数で万年業務カレンダー(日付固定)を作ってみる〜第4回〜前、翌営業日の計算(任意の休みの場合)

全5回に渡って、下のような万年業務カレンダーをつくっています。

記事の構成は下のようになっています。内容が重なるものはサラッと書きますので、詳しく知りたい方は、過去回をご確認ください。

万年業務カレンダーの作成全5回

今回は、任意の休みの場合の前営業日、翌営業日の計算です。
多くの場合、会社や業務によって、休みが違うでしょうから、前回の記事を読んで「土日休みの場合だけ説明されてもねぇ」と、思われた方はたくさんいらっしゃるのではないかと思います(笑)

そんなわけで、ちゃんと業務で使えるように、任意の休みの場合で計算したいと思います!

と、言いましても、、、、私はみなさんの休みを知りませんし、計算してわかるはずありません!(笑)
なので、休み一覧を別シートに準備し、それを参照して判定をする方法をとります!
このサンプルでは、過去記事の「関数で万年カレンダー(曜日固定)をつくってみる(後編)」で使った、内閣府が配布している祝日のCSVデータを別シートにコピーして使います。このデータの形ですが、A列に日付(年月日)、B列に祝日名が入っているものです。今回は祝日名は使わないので、みなさんは休みの日付がA列に並んでいるデータを準備していただければよいです。シート名は「休日」にします。

さて、予定の入出力方法は第3回と同じにして、日付の算出方法だけ変えていきます。

第3回のときは曜日で休み判定をしたので、WEEKDAY関数を使いましたね。今回は曜日で判断ができませんので使えません。どうするのかといいますと、、、、人間と同じように1日ずつ日付と休日を確認する方法でやっていきます。まあまあアナログな手法です(笑)

申し訳ないですが、もう1枚シートを準備してください。サンプルではシート名を「計算」としておきます。カレンダーも別シートから参照しますので、「カレンダー」というシート名をつけます。
シートばかり増やすのはあまり好きでな無い方は、予定を入力する表の右横を使っても構いません。ただ、その方法ですと、セルを0幅にしても関数が消されたり、崩されたりするリスクが出てきます。シートを別にして非表示させる方がまだ安全だと思いますので、一度、ご検討ください。

では、「計算」シートを使って、どのように前、翌営業日を算出するかですが、下のようなものを作って判定していきます。

このように実際に入力された予定日を起点に、前営業日なら前に、翌営業日なら後ろに1日ずつ3週ズラして判定するというアナログな方法です。VBAなら、配列にするとか、ループ判定するとかできるのですが、、、私のスキルで関数でなんとかというと、この方法しか思いつかなかったです。

では、実際に式を作っていきます。
「カレンダー」シートから参照するセルは、下の4つです。

そして、「計算」シートは下のように使います。

予定日を出力する式は、セルA2に、このように入力します。

=IF(カレンダー!M3="","",DATE(カレンダー!$C$1,カレンダー!$E$1,カレンダー!$M3))

「カレンダー」の予定設定の日付欄(セルM3)が空欄のときは空白を表示する条件分岐をつけてますが、「カレンダー」の参照先から年月日をそれぞれ指定してDATE関数で日付を表示させているだけです。

つぎは、休日判定の式です。
先程説明したように、判定の式は、当日の休日判定と3週分の判定と分けて考えていきます。式のすぐ横のセルB2に予定日当日、さらにその横のセルC2以降に1日ずつ横にズラして3週分判定していきます。
はじめにセルB2に入れる予定当日の休日判定です。

=IF(A2="","",COUNTIF(休日!$A:$A,A2))

「休日」シートのA列に休みの日付一覧が入ってますので、その中から、セルA2で作った予定日データと同じ日があればカウントするようにします。当然ですが、祝日と同じ日があれば「1」、なければ「0」になります。
そして、セルC2に入れる、予定日から1日ズラした休日判定です。

=IF(B2="","",COUNTIF(休日!$A:$A,$A2+(COLUMN()-2)*IF(カレンダー!$N3="前",-1,1)))

この式をD列側に向かって必要数コピーしていきます。サンプルでは3週分(21日分)にしてます。さすがに会社で3週連続で休むことは無いと思いますので、ここまでは必要ないかと思いますが、学校ならもっと必要かもしれませんね。このへんはご自身の環境にあわせて作成してください。

関数の説明ですが、やっていることは当日の判定式と同じです。当日はセルA2を参照していましたが、そこから1列ズレるごとに1日ズレた日付を参照しないといけませんので、セルA2から条件によって減算、加算をする式が入ってます。
COLUMN関数は 関数で万年カレンダー(曜日固定)をつくってみる(前編) で出てきましたね。列数を戻り値として使える関数です。列が増えていくことを利用して起点日から離れていく数字を表現し、オートフィルできるようにしています。
減算、加算の判定は、ユーザーからの入力結果(セルN3)を受けて変える式になっています。
減算、加算の式をそのまま書いてもいいのですが、予定日から1日ずつ3週間までズラす数字は、前だろうと、後ろだろうと変わらず、足すのか引くのかの違いだけです。なので、引く場合は「−1」を、足す場合は「+1」をズラす数字に掛けて減算、加算を変化させてます。
あとは、下方向に判定したい分だけコピーすればOKです。
もう、このままで十分良いのですが、3週分ズラして考えた式は、実は逆方向の当日にオートフィルすると、当日の計算になっちゃいます(笑)COLUNM関数から−2して増える数字を表現してますが、逆に戻すと予定日から0日ずらすになるわけです。要するに当日のことですね。考えやすいので分けてましたが、結局一緒の式で全部いけるということでした。関数の管理の上では一緒にしておいたほうが、あとあと整理するときに楽かもしれませんね。


さて、これで前、翌営業日によって起点となる予定日から3週間の状態がわかるようになりました。
この状態から、「0」を検索して計算に組み込めばいいだけです。もう探すといえば、、、、MATCH関数 です!MATCH関数のことは、過去記事で何回も何回も書いたので周知のものとして書いていきます(笑)

休みと営業日が横に並んでいる状態で、左から初めて現れる「0」の位置がわかればいいわけですから、まさにMATCH関数はうってつけですね。
今度は、「カレンダー」のセルN3の横、セルO3に

=IF(M3="","",IF(N3="",M3,M3+((MATCH(0,計算!B2:W2,0)-1)*IF(N3="前",-1,1))))

と入れて、必要な分だけ下方向にコピーします。
予定日からズラしたい日数をMATCH関数で調べています。加算するか減算するかの仕組みは、先程の休日判定のときと同じです。
そして、MATCH関数の戻り値から「ー1」をしています。これは、先程、「計算」シートで休日判定をしましたが、当日も含んで判定していました。そのため、ズラしたい日数に当日が入り込んでしまってますので、「−1」が必要なわけです。
これ、当日を外して参照すればよくない?と考えてしまいそうですが、そうしますと、当日が営業日だった場合、困ってしまいます。当日の判定のために、条件分岐を一つ増やさなければならないからです。そういうわけで、当日も含んで休みかどうかを判定し、当日の判定を別で考えなくていいというわけです。

そして、前、翌営業日を必ず指定する予定ばかりではありません。休日でも実施する予定もありえます。そういった場合は前後の指定をせずに空白にしてもらい、空白の場合はそのまま指定日を表示するという分岐をすればいいですね。

文章だけでつたわるのでしょうか(笑)一回図を作ってみたのですが、うまくまとめられなくて、、、、またまとめられたら記事を更新しますね。


さて、、、もう一つ。応用編です。今作ってきた仕組みでは、休み判定できる種類が1つだけですね。
でも、現実世界では会社の定休日、国民の祝日、曜日定休、、、と結構休みになる要素って多いですよね。このままですと、実用にはちょっと足りない感じです。

安心してください!はいて・・・、じゃない(笑)
実は!!この回でやってきた方法は、複数の休み要素もまとめて表現できます。
ベースはこのままです。「計算」シートに条件を追加していくだけです。
では、どうやって追加するのか?
実際に、土日休みの場合を式に入れてみましょう。ちょっと長くなるので改行とインデントつけていきます。

=IF(B2="","",
  COUNTIF(休日!$A:$A,$A2+(COLUMN()-2)*IF(カレンダー!$N3="前",-1,1))
    +
  IF(WEEKDAY($A2+(COLUMN()-2)*IF(カレンダー!$N3="前",-1,1),2)<6,0,1)
 )

 

先程の休日判定をした式に続いて、WEEKDAY関数で曜日判定した結果、土日なら「1」、それ以外は「0」を加算してます。 こんな感じで条件を加算していけばいいだけです。
前、翌営業日をMATCH関数で探すとき、営業日である「0」を探してました。
なので、休みの条件が重なって、「2」とか「3」になったとしても、「0」はすべての休み要素に関わらない休みということなんですね


さあ、これで第3回と同じ用に、前営業日、翌営業日が任意の日付でも対応表示されるようになりました。
あとは、この内容をカレンダーに予定を表示させるわけですが、、、第5回でやります(笑)
第5回では、別の予定設定をしたとき、予定が被っても2つ表示させられるようにします!

今回はすこし作成に時間がかかってしまいました。。。いい年して肉体労働のフリーターなんで、疲れて寝ちゃうんですよね(笑)
なんか文章ばかりでわかりにくいし、、、、なんか申し訳ないです。

それでは今回はここまでです。読んで頂きありがとうございました。