Update:


バッチ処理サンプル(その6)日付計算(再)


特定の曜日や日付を除いた日数(営業日数や平日の日数など)の計算

2つの日付から日数を求める処理は比較的簡単ですが、特定の日付や曜日を除いた日数計算は多少複雑なものとなります。
休日や曜日を除外するには除外する日の指定方法を工夫する必要があります。
ここでは、除外する日を曜日「w0〜w6」、週数曜日「m週数曜日」、月の日付「d日付」、月日「y月日」のように
指定して該当する日付かどうかチェックします。

Windows 2000、XPで使えるようになったバッチ引数や環境変数の拡張機能を利用して処理のパターン化を行います。
たいした処理はしていませんが、何かの参考や役に立てば幸いです。
※Windows 9x/meでは利用できません。ご了承ください。

日数計算の概要

●処理の目的と目標
 計算の開始日と終了日を指定し、その間の営業日数と休日日数(休業日数)を求めます。
 必要に応じて、計算の経過表示や振替休日の設定を行えるようにします。

●処理の条件
 1.休日の種類と指定方法は次の通りとします。
   ア.毎週固定曜日で指定する休日
    (w0:日曜、w1:月曜、w2:火曜、w3:水曜、w4:木曜、w5:金曜、w6:土曜)
   イ.毎月固定の日数で指定する休日(d日数、日数:01〜31)
   ウ.週数曜日で指定する休日(m週数曜日数、週数:1〜6、曜日数:0(日曜)〜6(土曜))
   エ.月日指定の休日(y月日、月:01(1月)〜12(12月)、日:01(1日)〜31(31日))
   オ.月週数曜日で指定する休日(h月週数曜日数、月:01〜12、週数:1〜6、曜日数:0〜6)
   カ.例外日(休日としない日)(e月日、月:01〜12、日:01〜31)
 2.振替休日は、あり/なしを選択できるように環境変数を設定しておくものとします。
 3.振替休日は、ア.毎週固定曜日の休日とイ.〜オ.で指定される休日が重なった場合のみ
   翌日を休日に設定します。
 4.休日は、バッチファイルの環境変数に直接設定します。
 5.計算の開始日と終了日はキーボードから入力します。
 6.計算の開始日と終了日は、半角数字で西暦年数(4ケタ)月(2ケタ)日(2ケタ)を半角記号「/、−、.」
   で区切って入力します。
   (例)2014/01/05→西暦2014年1月5日
 7.計算の開始日と終了日は2001/01/01(2001年1月1日)〜2100/12/31(2100年12月31日)の範囲で
   設定するものとします。
 8.計算の開始日が終了日よりも大きい場合は、開始日と終了日を入れ替えて計算するものとします。
 9.計算の途中経過の表示は、する/しないを選択できるように環境変数を設定しておくものとします。
 10.計算結果は、計算の対象期間の日数と営業日の日数、休業日の日数を表示します。

●計算処理の流れ
0.休日を設定
1.日数計算の開始日付と終了日付の入力
2.開始日付から終了日付まで検査対象日を変えながら以下を繰り返す
 2−1.検査対象の日付は休日か?
  2−1−1.はい:休日の日数+1→休日の日数
  2−1−2.   週休とほかの休日が重なっているか?
   2−1−2−1.   はい:振替休日の候補としてフラグをセットする。
   2−1−2−2.   いいえ:何もしない(次へ)
  2−1−3.いいえ:営業日の日数+1→営業日の日数
 2−2.検査結果を表示するか?
  2−2−1.はい:検査対象日と検査結果(休日または営業日)を表示する。
  2−2−2.いいえ:何もしない(次へ)
3.検査対象日の日数と営業日、休日を表示する。

ページトップへ戻る


プログラム

@title 営業日数計算
@echo off
PUSHD %~dp0
rem ===== 休日設定 ============================================================
rem 曜日設定 0..6 -> 日〜土 w9はダミーの曜日設定
set wday=w0 w6 w9
rem 日数での設定 d日数 日数:01〜31
set dday=d99
rem 週数曜日での設定 m週曜日曜数 m21→2週目の月曜日
set mday=m99
rem 月日設定 y0101・・y1231 1月1日〜12月31日
set yday=y0101 y0211 y0321 y0429 y0503 y0504 y0505 y0923 y1103 y1123 y1223 y9999
rem 月週曜日での設定 h0730->7月3週目日曜、h1025->10月2週目金曜 、h9999->ダミー設定
set hday=h0121 h0731 h0921 h1021 h9999
rem 例外日(休業日を営業日に振り替え) e1103->11月3日
set eday=e0402 e9999

rem ===== 処理設定 ============================================================
rem 振替休日 あり:1、なし:0
rem (wdayに設定した休業日とほかの休業日が重なった場合は翌日を振替休日とします。)
set /a f_sw = 1
rem 検査日付の表示(チェックした日付を表示します。)
set /a dsp_sw = 1

rem ==== 処理開始 =============================================================
rem 曜日の設定
set wd[0]=日
set wd[1]=月
set wd[2]=火
set wd[3]=水
set wd[4]=木
set wd[5]=金
set wd[6]=土

rem 月日数の設定
set /a md[0]=0
set /a md[1]=31
set /a md[2]=28
set /a md[3]=31
set /a md[4]=30
set /a md[5]=31
set /a md[6]=30
set /a md[7]=31
set /a md[8]=31
set /a md[9]=30
set /a md[10]=31
set /a md[11]=30
set /a md[12]=31

rem 年間の通算日数を計算
set /a yd[0]=0
for /L %%L in (1, 1, 12) do call :yd %%L

rem 開始日と終了日を設定(yyyy-mm-dd、yyyy.mm.dd も可)
set /p s=開始日(yyyy/mm/dd):
set /p e=終了日(yyyy/mm/dd):
if %s% GTR %e% call :swap

call :getdate %s%
set /a sy=%y% & set /a sm=%m% & set /a sd=%d%
call :getdate %e%
set /a ey=%y% & set /a em=%m% & set /a ed=%d%

rem 開始日付のエラーチェック
if %sy% LSS 2001 goto :OutOfRange lss-sy
if %sy% GTR 2100 goto :OutOfRange gtr-sy
call :uruu %sy%
if %sm% LSS 1 goto :OutOfRange lss-sm
if %sm% GTR 12 goto :OutOfRange gtr-sm
call set /a md = %%md[%sm%]%%
if %sm% EQU 2 set /a md+=%uruu%
if %sd% LSS 1 goto :OutOfRange lss-sd
if %sd% GTR %md% goto :OutOfRange gtr-sd

rem 終了日付のエラーチェック
if %ey% LSS 2001 goto :OutOfRange lss-ey
if %ey% GTR 2100 goto :OutOfRange gtr-ey
call :uruu %ey%
if %em% LSS 1 goto :OutOfRange lss-em
if %em% GTR 12 goto :OutOfRange gtr-em
call set /a md = %%md[%em%]%%
if %em% EQU 2 set /a md+=%uruu%
if %ed% LSS 1 goto :OutOfRange lss-ed
if %ed% GTR %md% goto :OutOfRange gtr-ed

call :days %sy% %sm% %sd%
set /a sdate=%days%
rem echo %sdate%

call :days %ey% %em% %ed%
set /a edate=%days%
rem echo %edate%

set /a flg = 0
set /a h = 0
set /a j = 0
if %f_sw% EQU 1 call :before
for /L %%L in (%sdate%, 1, %edate%) do call :holydaycheck %%L
echo.
set /a days = %edate% - %sdate% + 1
echo 調査日数=%days% , 営業日数=%j% , 休業日数=%h%

pause
POPD
exit /b

rem === ここからサブルーチン ==================================================
rem 引数ので与えられた日(西暦1年1月1日からの通算日数)が休日かどうかを調べます。
:holydaycheck
set /a fuldays = %1
rem 693961 -> 1900/12/31=1901/01/00
rem 10000倍することで、1年の日数を365.2425→3652425で表します。(小数点を外します。)
set /a days = (%fuldays% - 693961) * 10000
set /a y = %days% / 3652425
set /a year = %y% + 1901
rem 引数で与えられた日付の曜日を求めます。(0→日、1→月、2→火〜6→土)
set /a w = %fuldays% %% 7
rem 閏年のチェックを行います。
set /a uruu = 0
call :uruu %year%
set /a d = (%days% / 10000) - ((%y% * 3652425) / 10000)
rem 年初(1月1日)から各月の朔日(1日:ついたち)までの経過日数を使い月数を求めます。
set /a m = 12
:loop
    rem 月数が2月以下なら閏日は算入しません。(0日とする)
    if %m% LEQ 2 set /a uruu = 0
    call set /a yd = %%yd[%m%]%% + %uruu%
    if %d% GTR %yd% goto :exit-loop
    set /a m -= 1
    goto :loop
:exit-loop
rem m月d日を求めます。
set /a d = %d% - %yd%
rem dの日数を2桁表示でddに設定します。
set /a dd = %d% + 100
set dd=%dd:~-2%
rem mの月数を2桁表示でmmに設定します。
set /a mm = %m% + 100
set mm=%mm:~-2%
rem ymdwに年月日[曜日]を設定します。
call set ymdw=%year%/%mm%/%dd%_%%wd[%w%]%%_

rem 休日チェックのデータを作ります。(week:週数、mw:週数曜日、yd:月日、hd:月数週数曜日)
set /a week=(%d% - %w% + 6) / 7
set mw=%week%%w%
set yd=%mm%%dd%
set hd=%mm%%mw%
set ed=%yd%

rem 休日のチェックリストとなる文字列を作成します。
set wdd=%wday%
set ddd=%dday%
set mdd=%mday%
set ydd=%yday%
set hdd=%hday%
set edd=%eday%
rem 曜日での休業日であることを示すフラグをリセットしておきます。
set /a wflg = 0
rem チェック対象の曜日が曜日のリストにあれば、削除します。
call set wdd=%%wdd:w%w%=%%
rem 曜日のチェック文字列と休業日のリスト文字列が一致しなければ、休業日とします。
if not "%wdd%" == "%wday%" set /a flg=1 & set /a wflg=1
rem 日数で休業日のチェックを行います。
call set ddd=%%ddd:d%dd%=%%
if not "%ddd%" == "%dday%" set /a flg = %wflg% + 1
rem 週数と曜日で休業日のチェックを行います。
call set mdd=%%mdd:m%mw%=%%
if not "%mdd%" == "%mday%" set /a flg = %wflg% + 1
rem 月日で休業日のチェックを行います。
call set ydd=%%ydd:y%yd%=%%
if not "%ydd%" == "%yday%" set /a flg = %wflg% + 1
rem 月と週数と曜日で休業日のチェックを行います。
call set hdd=%%hdd:h%hd%=%%
if not "%hdd%" == "%hday%" set /a flg = %wflg% + 1
rem 月日で休業日としない(営業日となる)例外日のチェックを行います。
call set edd=%%edd:e%ed%=%%
if not "%edd%" == "%eday%" set /a flg = 0

rem 0 < flg ならば休業日に1を加え、違っていれば(0 = flg)営業日に1を加える。
if %flg% GTR 0 (set /a h+=1) else (set /a j+=1)
rem 0 < flg ならばh_flgを休に、違っていれば(0 = flg)h_flgを_にセットする。
if %flg% GTR 0 (set h_flg=休) else (set h_flg=_)
rem 0 < dsp_sw ならば日付と"休"または"_"(=営業日)を表示する。
if %dsp_sw% GTR 0 set /p dmy=%ymdw%[%h_flg%] < NUL
rem 1 < flg ならflgを1(振替休日の候補)に、違っていればflgを0にセットする。
if %flg% GTR 1 (set /a flg=1) else (set /a flg=0)
rem 0 = f_sw ならflgを0にセットする。(振替休日を使わない)
if %f_sw% EQU 0 set /a flg=0
exit /b

rem -------------------------------------------------------------------
rem 開始日の前日が休業日であるかチェックする。>
:before
set days = (%sdate% - 693961) * 10000
set /a y = (%days% - 10000) / 3652425
set /a year = %y% + 1901
set /a w = (%sdate% - 1) %% 7
set /a uruu = 0
call :uruu %year%
set /a d = (%days% / 10000) - ((%y% * 3652425) / 10000)
set /a m = 12
:loop_01
if %m% LEQ 2 set /a uruu = 0
call set /a yd = %%yd[%m%]%% + %uruu%
if %d% GTR %yd% goto :exit-loop_01
set /a m -= 1
goto :loop_01
:exit-loop_01
set /a d = %d% - %yd%
set /a dd = %d% + 100
set dd=%dd:~-2%
set /a mm = %m% + 100
set mm=%mm:~-2%
set /a week=(%d% - %w% + 6) / 7
set mw=%week%%w%
set yd=%mm%%dd%
set hd=%mm%%mw%
set ed=%yd%

set wdd=%wday%
set mdd=%mday%
set ydd=%yday%
set hdd=%hday%
set edd=%eday%

set /a wflg=0
if not "%wdd%" == "%wday%" set /a wflg = 1
call set mdd=%%mdd:m%mw%=%%
if not "%mdd%" == "%mday%" set /a flg = %wflg%
call set ydd=%%ydd:y%yd%=%%
if not "%ydd%" == "%yday%" set /a flg = %wflg%
call set hdd=%%hdd:h%hd%=%%
if not "%hdd%" == "%hday%" set /a flg = %wflg%
call set edd=%%edd:e%ed%=%%
if not "%edd%" == "%eday%" set /a flg = 0
if %f_sw% EQU 0 set /a flg=0
exit /b

rem -------------------------------------------------------------------
rem 西暦年、月、日から西暦元年(1年)1月1日(=1日)からの通算日数を求めます。
:days
set /a y = %1-1
set /a m = %2
set /a d = %3
set /a days = %y% * 365 + (%y% / 4) - (%y% / 100) + (%y% / 400)
call set /a days += %%yd[%m%]%%
set /a days += %d%
set /a uruu = 0
if %m% GTR 2 call :uruu %1
set days += %uruu%
exit /b

rem -------------------------------------------------------------------
rem 日付(yyyy/mm/dd)をy年(yyyy)、m月(mm)、d日(dd)に分解します。
:getdate
set dt=%~1
set dt=%dt:/= %
set dt=%dt:-= %
set dt=%dt:.= %
for /f "tokens=1-3" %%I in ("%dt%") do set y=%%I&set m=%%J&set d=%%K
exit /b

rem -------------------------------------------------------------------
rem 環境変数eとsの内容を入れ替えます。
:swap
set w=%e%
set e=%s%
set s=%w%
exit /b

rem -------------------------------------------------------------------
rem 1年の中で各月の1日までに経過している日数(=前月の末日までの日数)を求めます。
:yd
set /a b=%1-1
call set /a yd[%1] = %%yd[%b%]%% + %%md[%b%]%%
exit /b

rem -------------------------------------------------------------------
rem 閏年のチェックを行い、閏年であればuruuを1に、閏年でなければuruuを0にセットします。
:uruu
set /a u = %1
set /a r4 = u%%4
set /a r100 = u%%100
set /a r400 = u%%400
set uruu=0
if %r4% EQU 0 set uruu=1
if %r100% EQU 0 set uruu=0
if %r400% EQU 0 set uruu=1
exit /b

rem -------------------------------------------------------------------
rem エラーメッセージを表示します。
:OutOfRange
if "%1" == "lss-sy" echo 開始年は2001年以上2100年以下で設定してください。 & goto :EOF
if "%1" == "gtr-sy" echo 開始年は2001年以上2100年以下で設定してください。 & goto :EOF
if "%1" == "lss-sm" echo 開始月は1以上12以下で設定してください。 & goto :EOF
if "%1" == "gtr-sm" echo 開始月は1以上12以下で設定してください。 & goto :EOF
if "%1" == "lss-sd" call echo 開始日は1以上%%md[%sm%]%%以下で設定してください。 & goto :EOF
if "%1" == "gtr-sd" call echo 開始日は1以上%%md[%sm%]%%以下で設定してください。 & goto :EOF

if "%1" == "lss-ey" echo 終了年は2001年以上2100年以下で設定してください。 & goto :EOF
if "%1" == "gtr-ey" echo 終了年は2001年以上2100年以下で設定してください。 & goto :EOF
if "%1" == "lss-em" echo 終了月は1以上12以下で設定してください。 & goto :EOF
if "%1" == "gtr-em" echo 終了月は1以上12以下で設定してください。 & goto :EOF
if "%1" == "lss-ed" call echo 終了日は1以上%%md[%em%]%%以下で設定してください。 & goto :EOF
if "%1" == "gtr-ed" call echo 終了日は1以上%%md[%em%]%%以下で設定してください。 & goto :EOF
goto :EOF



ページトップへ戻る


【ページ内見出し】
【サイト内リンク】

−広告エリア−



元のページに戻る  ページを閉じる

連絡先:お問い合わせフォーム