【Python実践プロジェクト】datetimeと正規表現(re)で作る!未来時刻計算ツール開発チュートリアル 🛠️
「3日と5時間40分後って、具体的に何月何日の何時何分だろう?」
「Pythonの勉強を一通りしたけど、実際に何か便利なものを作ってみたい!」
「これまで学んだ標準ライブラリの知識、どうやって組み合わせればいいんだろう?」
こんにちは! Pythonistaの皆さん、これまでの標準ライブラリ探検、お疲れ様でした! これまでに、日付を扱うdatetime
や、複雑な文字列を解析するre
など、たくさんの強力な武器を手に入れてきましたね。
今回は、これまでのシリーズとは少し趣向を変えた「実践プロジェクト編」です! これまで学んだ知識を総動員して、日常のちょっとした疑問を解決してくれる便利なツール、「未来時刻計算ツール」をゼロから作り上げていきましょう。このツールは、「3d23h50m」
(3日23時間50分後)や「12:40」
(12時間40分後)といった様々な形式の時間を入力すると、現在の時刻からその時間だけ未来の正確な日時を計算してくれます。
この記事を読みながら一緒にコーディングを進めれば、あなたも実用的なPythonツールを完成させることができます。さあ、学んだ知識を形にする楽しさを味わいましょう!
1. 今回作るツール:どんな問題を解決する?(設計図を描こう)
プログラムを作り始める前に、まず「何を作るのか」「どんな機能が必要か」を明確にするのが成功の秘訣です。今回作成する「未来時刻計算ツール」の主な機能は以下の通りです。
- ユーザーからの柔軟な入力受付: ユーザーが様々な形式で経過時間を入力できるようにします。
- 例1:
3d23h50m
(日・時間・分の組み合わせ) - 例2:
12:40
(コロン区切りの時間・分) - 例3:
5h
や30m
といった単一単位 - 例4:
50m 1d
のように、単位の順序がバラバラでも、スペースが含まれていてもOK
- 例1:
- 現在時刻の取得と未来時刻の計算: プログラム実行時の現在時刻を基準に、入力された時間だけ未来の時刻を正確に計算します。
- 結果の分かりやすい表示: 計算前の現在時刻、入力された経過時間、そして計算後の未来時刻を、人間が読みやすい形式で表示します。
このツールを実現するために、以下の標準ライブラリが中心的な役割を果たします。
datetime
モジュール: 現在時刻の取得 (datetime.now()
) や、時間の差分・期間を扱う (timedelta
)、そして結果の表示形式を整える (strftime()
) ために使います。re
モジュール (正規表現):「3d23h50m」
や「12:40」
といった多様なユーザー入力を柔軟に解析するために使います。まさに正規表現の腕の見せ所です!
2. ステップ1:プロジェクトの骨格と基本の時刻計算
まずは、プログラム全体の骨格と、中核となる時刻計算の基本部分から作っていきましょう。
from datetime import datetime, timedelta
def main():
"""
メイン処理。ユーザーとの対話、計算、結果表示を行う。
"""
print("🚀 未来時刻計算スクリプト 🚀")
print("経過時間を入力してください。")
print("例: 3d23h50m (3日23時間50分), 12:40 (12時間40分), 1d12h (1日と12時間)")
# --- まずは固定の時間で計算の基本を試してみる ---
now = datetime.now()
fixed_delta = timedelta(days=3, hours=23, minutes=50) # 3d23h50m をtimedeltaで表現
future_time = now + fixed_delta
print("\n--- 計算テスト ---")
print(f"現在時刻 : {now.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"経過時間 : {str(fixed_delta)}")
print(f"未来の時刻: {future_time.strftime('%Y-%m-%d %H:%M:%S')}")
print("------------------")
# --- ここまでが基本テスト ---
# このスクリプトが直接実行された場合にのみmain()関数を呼び出す
if __name__ == "__main__":
main()
このコードを実行すると、現時点での時刻と、そこから3日23時間50分後の時刻が表示されるはずです。datetime
オブジェクトとtimedelta
オブジェクトの足し算で未来の時刻が簡単に計算できることが分かりますね。私たちの最終目標は、このfixed_delta
の部分を、ユーザーの入力から動的に生成することです。
3. ステップ2:ユーザー入力を解析する心臓部!parse_time_input()
関数
ここが今回のプロジェクトの最も面白く、挑戦的な部分です。「50m 1d」
のような順序がバラバラな入力や、「12:40」
のような異なる形式をどうやって一つの時間に変換するか。ここで正規表現(re
モジュール)が活躍します。
以下のような、ユーザーの多様な時間入力を解析してtimedelta
オブジェクトを返す関数を作成します。
import re
from datetime import timedelta
def parse_time_input(input_str: str) -> timedelta | None:
"""
ユーザーの多様な時間入力を解析してtimedeltaオブジェクトを返す。
順序不同の入力 (例: 50m3d23h) やスペースを含む入力にも対応。
Args:
input_str (str): ユーザーによって入力された時間文字列。
Returns:
timedelta | None: 解析に成功した場合はtimedeltaオブジェクト、
失敗した場合はNoneを返す。
"""
# 入力からスペースを削除し、全て小文字に変換して処理を簡単にする
clean_str = input_str.strip().lower().replace(" ", "")
days = 0
hours = 0
minutes = 0
# --- d, h, m を含む形式の解析 ---
# re.findall() を使って、各単位の数値を文字列中から全て見つけ出す
days_list = re.findall(r'(\d+)d', clean_str) # 例: "3d" -> ['3']
hours_list = re.findall(r'(\d+)h', clean_str) # 例: "23h" -> ['23']
minutes_list = re.findall(r'(\d+)m', clean_str) # 例: "50m" -> ['50']
# --- コロン(:) を含む形式の解析 ---
# 文字列の先頭(^)から末尾($)までが「数字:数字」のパターンに完全に一致するかチェック
colon_match = re.match(r'^(\d+):(\d+)$', clean_str)
# --- 解析結果を時間に変換 ---
is_dhm_format = days_list or hours_list or minutes_list
if is_dhm_format:
# 同じ単位が複数回指定されても対応できるよう、見つけた数値を全て合計する
days = sum(map(int, days_list))
hours = sum(map(int, hours_list))
minutes = sum(map(int, minutes_list))
# d, h, m と数字以外の不正な文字がないかチェック
check_str = re.sub(r'\d+d|\d+h|\d+m', '', clean_str)
if check_str:
return None # 無効な文字が残っていれば解析失敗
return timedelta(days=days, hours=hours, minutes=minutes)
elif colon_match:
# コロン形式の場合は、マッチしたグループから時間と分を取得
hours = int(colon_match.group(1))
minutes = int(colon_match.group(2))
return timedelta(hours=hours, minutes=minutes)
else:
# どの形式にも一致しない場合は失敗
return None
この関数のポイント:
- 入力の前処理:
.strip().lower().replace(" ", "")
で、大文字・小文字、前後の空白、途中のスペースを吸収し、後続の正規表現処理をシンプルにしています。 re.findall(r'(\d+)d', ...)
: 文字列全体から「数字+d」
というパターンを全て探し出し、数字の部分だけをリストとして返します。(\d+)
の括弧が「キャプチャグループ」となり、この部分だけが結果として得られます。h
,m
も同様です。re.match(r'^(\d+):(\d+)$', ...)
: 文字列の先頭からパターンが一致するかを試します。^
は文字列の先頭、$
は末尾を意味するため、「12:30abc」
のような余計な文字が含まれている入力を不正として弾くことができます。sum(map(int, ...))
:findall
が返すのは文字列のリスト(例:['1', '2']
)なので、map(int, ...)
で各要素を整数に変換し、sum()
で合計しています。これにより「1d 2d」
のような入力も正しく「3日」として扱えます。
4. ステップ3:全てを統合!未来時刻計算ツールの完成形
それでは、ステップ1で作った骨格と、ステップ2で作った入力解析関数を組み合わせて、ツールを完成させましょう!
import re
from datetime import datetime, timedelta
# (ここに、上記で作成した parse_time_input() 関数を貼り付ける)
def parse_time_input(input_str: str) -> timedelta | None:
# ... (内容はステップ2と同じ) ...
clean_str = input_str.strip().lower().replace(" ", "")
days_list = re.findall(r'(\d+)d', clean_str)
hours_list = re.findall(r'(\d+)h', clean_str)
minutes_list = re.findall(r'(\d+)m', clean_str)
colon_match = re.match(r'^(\d+):(\d+)$', clean_str)
is_dhm_format = days_list or hours_list or minutes_list
if is_dhm_format:
days = sum(map(int, days_list))
hours = sum(map(int, hours_list))
minutes = sum(map(int, minutes_list))
check_str = re.sub(r'\d+d|\d+h|\d+m', '', clean_str)
if check_str: return None
return timedelta(days=days, hours=hours, minutes=minutes)
elif colon_match:
hours = int(colon_match.group(1))
minutes = int(colon_match.group(2))
return timedelta(hours=hours, minutes=minutes)
else:
return None
def main():
"""
メイン処理。ユーザーとの対話、計算、結果表示を行う。
"""
print("🚀 未来時刻計算スクリプト 🚀")
print("経過時間を入力してください。")
print("例: 3d23h50m (3日23時間50分), 12:40 (12時間40分), 1d12h (1日と12時間)")
while True:
try:
user_input = input("\n経過時間を入力してください (終了するには 'q' を入力): ")
if user_input.lower() == 'q':
print("スクリプトを終了します。")
break
if not user_input:
print("⚠️ 入力がありません。もう一度入力してください。")
continue
# 入力文字列を解析してtimedeltaを取得
time_delta = parse_time_input(user_input)
if time_delta:
now = datetime.now()
future_time = now + time_delta
print("-" * 40)
print(f"現在時刻 : {now.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"経過時間 : {str(time_delta)}")
print(f"未来の時刻: {future_time.strftime('%Y-%m-%d %H:%M:%S')}")
print("-" * 40)
else:
print("❌ 無効な形式です。もう一度入力してください。")
print("例: 3d23h50m, 12:40, 1d, 5h, 30m")
except KeyboardInterrupt:
print("\nスクリプトを中断しました。")
break
except Exception as e:
print(f"エラーが発生しました: {e}")
if __name__ == "__main__":
main()
使い方と実行例
- 上記のコード全体をコピーし、
future_time_calculator.py
のような名前でファイルを保存します。 - ターミナルやコマンドプロンプトを開き、以下のコマンドでスクリプトを実行します。
python future_time_calculator.py
- 画面の指示に従って、色々な形式で経過時間を入力してみてください!
🚀 未来時刻計算スクリプト 🚀 経過時間を入力してください。 例: 3d23h50m (3日23時間50分), 12:40 (12時間40分), 1d12h (1日と12時間) 経過時間を入力してください (終了するには 'q' を入力): 1d 12h ---------------------------------------- 現在時刻 : 2025-06-08 21:00:00 経過時間 : 1 day, 12:00:00 未来の時刻: 2025-06-10 09:00:00 ---------------------------------------- 経過時間を入力してください (終了するには 'q' を入力): 50m 2d ---------------------------------------- 現在時刻 : 2025-06-08 21:00:30 経過時間 : 2 days, 0:50:00 未来の時刻: 2025-06-10 21:50:30 ---------------------------------------- 経過時間を入力してください (終了するには 'q' を入力): 10:30 ---------------------------------------- 現在時刻 : 2025-06-08 21:01:00 経過時間 : 10:30:00 未来の時刻: 2025-06-09 07:31:00 ---------------------------------------- 経過時間を入力してください (終了するには 'q' を入力): q スクリプトを終了します。
5. まとめ:標準ライブラリの組み合わせでアイデアを形に!
今回は、これまでの学習内容を組み合わせる実践プロジェクトとして、「未来時刻計算ツール」を作成しました。このプロジェクトを通して、
datetime
モジュールを使った実践的な時刻計算。re
モジュール(正規表現)を使った、柔軟で強力な文字列解析。- 関数を使って処理を部品化し、プログラム全体を構造化する考え方。
while
ループとinput()
関数を使った、ユーザーとの対話的なプログラムの作り方。
といった、多くの重要なテクニックを体験することができました。
プログラムは、このように基本的な部品(関数やモジュール)を一つずつ作り、それらを組み合わせていくことで完成します。今回のツールをベースに、さらに機能を追加してみる(例: 秒(s)や週(w)に対応させる、過去の日時を計算できるようにする、GUIを追加する)のも、素晴らしい学習になるはずです。
自分で考えたアイデアを、Pythonという強力な道具を使って形にする楽しさを、これからもぜひ味わっていってください。応援しています!
次回は【Pillow入門 第1回】Pythonで画像処理をはじめよう!読み込み・リサイズ・回転・切り抜きも自由自在 🖼️✨
コメント
コメントを投稿