bat ファイルで日付を扱う方法 (Python 編)
こちらの記事で、bat ファイルと PowerShell を組み合わせて日付を扱う方法を紹介しましたが、Python でも同様のことができます。
→ bat ファイルで日付を扱う方法 (PowerShell 編)
bat ファイルを実行する環境が Python を実行できる環境で、PowerShell よりも Python の方がが好き!という人にはおすすめです。
あらすじ
年月 (YYYYMM 形式) を入力するとその年月のフォルダ名のフォルダを別の場所にコピーして、翌月のフォルダ名のフォルダを作成するといったような内容の bat ファイルがありました。
たとえば「 202201 」と入力すると 202201 という名前のフォルダをコピーして、 202202 というフォルダを作成するという風な感じです。
月次報告用の資料をまとめる業務を半自動化するために作成された bat ファイルなのですが、これが正しく動作しないという現象が発生しました。
202112 と入力したところ 202201 というフォルダが作成されるはずが 202113 というフォルダが作成されてしまったのです。
結論からいうと、「翌月」を算出する処理がコマンドラインから入力された年月に +1 するだけというとっても乱暴な作りだったことが原因でした。
こんな感じでした。
set /P user_input="年月を入力してね: "
set /a next_month=%user_input%+1
202201 と入力すると変数 next_month は 202202 となるのでこの場合は正しく動作します。
ですが、202112 と入力すると変数 next_month は 202113 となってしまいます。202201 とはなりません。
数値 202112 に 1 を足せば 202113 になるのは当然ですよね。
人間がこの数字の羅列を見たら日付に変換して考えますが、コンピュータからしたらただの整数値です。
bat ファイルで日付を扱う方法を考える
プログラミング言語で日付を扱う場合は数値から日付型を生成できますが、bat ファイル単体だと日付型のようなものは使用できません。
日付の処理は bat ファイル単体だと大変なので、Python を使う方法を紹介します。
bat ファイルから Python のスクリプト(py ファイル)を呼び出して bat の処理に戻すというような流れになります。
bat ファイルから py ファイルを実行して戻り値を変数に格納する
bat ファイルから py ファイルを実行するだけなら次のようにすればできます。
python test1.py
戻り値を変数に格納するには次のようにします。
rem 変数 data に戻り値を格納
FOR /F "usebackq" %%i IN (`python test1.py`) DO SET data=%%i
Python に引数を渡したい場合はファイル名の後ろに追加するだけで OK です。
set /P user_input="何か入力してね: "
FOR /F "usebackq" %%i IN (`python test1.py %user_input%`) DO SET data=%%i
Python でコマンドライン引数を受け取る
Python では sys モジュール argv にコマンドライン引数が格納されます。
第 1 引数は argv[1]、第 2 引数は argv[2] といった感じで取得できます。
argv[0] にはスクリプトのファイル名が格納されています。
import sys
print(sys.argv[1])
Python で日付の計算をする
Python で日付を扱う場合は datetime モジュールをインポートする必要があります。
また、datetime モジュールでは日や時の加減算はできますが、年や月の加減算はできないので別途 dateutil モジュールが必要になります。
dateutil モジュールは組込みモジュールではないので pip 等でインストールします。
pip install python-dateutil
まずは文字列を datetime.datetime 型に変換します。
from datetime import datetime
date1 = datetime.strptime('202112', "%Y%m")
print(date1) # 2021-12-01 00:00:00
日にちまで指定する場合は次のようにします。
from datetime import datetime
date2 = datetime.strptime('20211231', "%Y%m%d")
print(date2) # 2021-12-31 00:00:00
datetime.datetime 型にすることで日付の加減算が簡単にできるようになります。
日付を加減算するには dateutil モジュールの relativedelta オブジェクトを使用します。
from dateutil.relativedelta import relativedelta
print(date1 + relativedelta(months=1)) # 2022-01-01 00:00:00
print(date1 + relativedelta(months=-1)) # 2021-11-01 00:00:00
print(date2 + relativedelta(months=3)) # 2022-03-31 00:00:00
print(date2 + relativedelta(months=-3)) # 2021-09-30 00:00:00
Python から bat へ値を返す
bat へ値を返すには sys モジュール stdout.write メソッドを使用します。
ただし、bat で受け取れるのは文字列だけなので少し注意が必要です。
datetime.datetime 型をそのまま返すと bat では空白文字になります。
必ず文字列に変換する必要があります。
そのため、datetime.datetime 型の strftime メソッドで必要な形式の文字列に変換します。
from datetime import datetime
from dateutil.relativedelta import relativedelta
date = datetime.strptime(sys.argv[1], "%Y%m")
next_month = date + relativedelta(months=1)
sys.stdout.write(next_month.strftime("%Y%m"))
sys.exit(0)
こうすることで bat 側で 「 202201 」というような形式の文字列が受け取れます。
年月を入力すると翌月を表示する bat ファイルの例
以上を踏まえたうえで bat ファイルと py ファイルを作ってみましょう。
@echo off
set /P user_input="年月を入力してね(YYYYMM): "
FOR /F "usebackq" %%i IN (`python test.py %user_input%`) DO SET next_month=%%i
echo %user_input% の翌月は %next_month% だよ。
pause
import sys
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
try:
date = datetime.strptime(sys.argv[1], "%Y%m")
next_month = date + relativedelta(months=1)
sys.stdout.write(next_month.strftime("%Y%m"))
sys.exit(0)
except:
pass
test1.bat を実行して確認してみましょう。
正しい形式で年月を入力しないと変数 next_month は空白文字になります。
変数 next_month が空白文字かどうかを判定することで入力チェックの処理を作ることもできるのでぜひ挑戦してみてください。