bat ファイルで日付を扱う方法 (Python 編)

2022年1月10日 2023年11月8日
カテゴリ: プログラミング
Python Windows batファイル

こちらの記事で、bat ファイルと PowerShell を組み合わせて日付を扱う方法を紹介しましたが、Python でも同様のことができます。
bat ファイルで日付を扱う方法 (PowerShell 編)

bat ファイルを実行する環境が Python を実行できる環境で、PowerShell よりも Python の方がが好き!という人にはおすすめです。

あらすじ

年月 (YYYYMM 形式) を入力するとその年月のフォルダ名のフォルダを別の場所にコピーして、翌月のフォルダ名のフォルダを作成するといったような内容の bat ファイルがありました。
たとえば「 202201 」と入力すると 202201 という名前のフォルダをコピーして、 202202 というフォルダを作成するという風な感じです。
月次報告用の資料をまとめる業務を半自動化するために作成された bat ファイルなのですが、これが正しく動作しないという現象が発生しました。

202112 と入力したところ 202201 というフォルダが作成されるはずが 202113 というフォルダが作成されてしまったのです。
結論からいうと、「翌月」を算出する処理がコマンドラインから入力された年月に +1 するだけというとっても乱暴な作りだったことが原因でした。

こんな感じでした。

bat
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 ファイルを実行するだけなら次のようにすればできます。

bat
python test1.py

戻り値を変数に格納するには次のようにします。

bat
rem 変数 data に戻り値を格納
FOR /F "usebackq" %%i IN (`python test1.py`) DO SET data=%%i

Python に引数を渡したい場合はファイル名の後ろに追加するだけで OK です。

bat
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] にはスクリプトのファイル名が格納されています。

Python
import sys
print(sys.argv[1])

Python で日付の計算をする

Python で日付を扱う場合は datetime モジュールをインポートする必要があります。
また、datetime モジュールでは日や時の加減算はできますが、年や月の加減算はできないので別途 dateutil モジュールが必要になります。
dateutil モジュールは組込みモジュールではないので pip 等でインストールします。

pip install python-dateutil

まずは文字列を datetime.datetime 型に変換します。

Python
from datetime import datetime
date1 = datetime.strptime('202112', "%Y%m")
print(date1) # 2021-12-01 00:00:00

日にちまで指定する場合は次のようにします。

Python
from datetime import datetime
date2 = datetime.strptime('20211231', "%Y%m%d")
print(date2) # 2021-12-31 00:00:00

datetime.datetime 型にすることで日付の加減算が簡単にできるようになります。

日付を加減算するには dateutil モジュールの relativedelta オブジェクトを使用します。

Python
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 メソッドで必要な形式の文字列に変換します。

Python
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 ファイルを作ってみましょう。

test1.bat
@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
test1.py
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 が空白文字かどうかを判定することで入力チェックの処理を作ることもできるのでぜひ挑戦してみてください。

関連の記事

OpenPyXl でチェックボックスを押したい

【Django】CSS や JavaScript の変更が反映されないときの対処法

Sphinxで作ったドキュメントの外部リンクを新しいタブで開く方法を考える

「GAKKOU」 問題を Python で解いてみよう