Pythonの日付操作【プログラミング初心者向け教材】

プログラミング

日付の生成、加算・減算、比較、フォーマットなどの操作は、プログラミングでよくある操作の1つです。

データベースやAPIなどで外部と日付データを送受信する際には、決まったフォーマットにする必要があります。

そのため、プログラミング初心者にとって、日付操作は学習すべき事項の1つとなります。

本記事では、Pythonのよく使われる日付操作について解説します。

プログラミング初心者の方の学習や、忘れてしまった方の復習として、参考にしていただければ幸いです。

記載しているプログラムは、Python3.6.8を使って動作確認をしています。

Pythonの日付操作

よくある日付操作として、以下の内容を採り上げます。

  • 日付を扱うクラス
  • 日時の生成
  • 日時・曜日の取得
  • 日時の加算・減算
  • 日時の差分
  • 日時の比較
  • 日時から文字列へのフォーマット
  • 文字列から日時への変換
  • ライブラリの利用

日時を扱うクラス

Pythonで日付を扱うクラスには以下があります。

  • datetimeクラス:日付と時刻を両方扱う
  • date:日付のみ扱う
  • time:時刻のみ扱う
  • timedelta:時間差を扱う

上記の4クラスはいずれも標準で提供されるdatetimeモジュールに含まれるクラスです。
今回は主に、datetimeクラスについて説明していきます。

日時の生成

日時を扱うdatetimeクラスを生成するには、大きく2つの方法があります。

現在時刻で生成する方法

d = datetime.datetime.today()
print(d) # -> 2020-10-20 09:36:20.951901
d = datetime.datetime.now()
print(d) # -> 2020-10-20 09:36:20.952064

任意の日時を指定して生成する方法

d = datetime.datetime(2020, 10, 20, 9, 33, 3)
print(d) # -> 2020-10-20 09:33:03
d = datetime.datetime(2020, 10, 20)
print(d) # -> 2020-10-20 00:00:00

別々の日付と時刻から生成する方法

date = datetime.date(2020, 10, 20)
time = datetime.time(9, 33, 33)
d = datetime.datetime.combine(date, time)
print(d) # -> 2020-10-20 09:33:33

日時・曜日の取得

日時の各属性値を取得する方法

日時のそれぞれの属性にアクセスすることで値を取得することができます。

d = datetime.datetime(2020, 10, 20, 9, 1, 2)
print(d.year) # -> 2020
print(d.month) # -> 10
print(d.day) # -> 20
print(d.hour) # -> 9
print(d.minute) # -> 1
print(d.second) # -> 2
print(d.microsecond) # -> 0

曜日を取得する方法

曜日の取得は、weekdayを使います。戻り値は0~6で以下の意味となります。

0:月曜日、1:火曜日、2:水曜日、3:木曜日、4:金曜日、5:土曜日、6:日曜日

他の言語と比較すると、0が月曜日である点に違和感を感じる方もいるかもしれません。isoweekdayを使うと、以下の意味で戻り値を得られます。

1:月曜日、2:火曜日、3:水曜日、4:木曜日、5:金曜日、6:土曜日、7:日曜日
d = datetime.datetime(2020, 10, 20) # 2020/10/20は火曜日
print(d.weekday()) # -> 1
print(d.isoweekday()) # -> 2

日時情報をタプルで取得する方法

日時情報をまとめたタプルに変換することもできます。タプルはtime.struct_timeというクラスになります。

d = datetime.datetime(2020, 10, 20, 9, 1, 2)
t = d.timetuple()
print(t) # -> time.struct_time(tm_year=2020, tm_mon=10, tm_mday=20, tm_hour=9, tm_min=1, tm_sec=2, tm_wday=1, tm_yday=294, tm_isdst=-1)

tm_ydayはその年の1月1日から経過日を表します。
tm_isdstは夏時間が有効な場合は1、無効の場合は0、不明な場合は-1となります。

日付情報(date)を取得する方法

datetimeからdateに変換するにはdateを使います。

d = datetime.datetime(2020, 10, 20, 9, 1, 2)
date = d.date()
print(date) # -> 2020-10-20

時刻情報(time)を取得する方法

datetimeからtimeに変換するにはtimeを使います。

d = datetime.datetime(2020, 10, 20, 9, 1, 2)
time = d.time()
print(time) # -> 09:01:02

日時の加算・減算

日時の加算や減算を行うには、datetimeオブジェクトに対して、timedeltaオブジェクトを加算・減算します。

日時の加算

timedeltaのコンストラクタに加算したい値を引数で指定します。
weeksは1を7日として計算します。

d = datetime.datetime(2020, 1, 1)
print(d + datetime.timedelta(days=1)) # -> 2020-01-02 00:00:00
print(d + datetime.timedelta(hours=2)) # -> 2020-01-01 02:00:00
print(d + datetime.timedelta(minutes=3)) # -> 2020-01-01 00:03:00
print(d + datetime.timedelta(seconds=4)) # -> 2020-01-01 00:00:04
print(d + datetime.timedelta(milliseconds=5)) # -> 2020-01-01 00:00:00.005000
print(d + datetime.timedelta(microseconds=6)) # -> 2020-01-01 00:00:00.000006
print(d + datetime.timedelta(weeks=7)) # -> 2020-02-19 00:00:00

日時の減算

timedeltaのコンストラクタに減算したい値を引数を指定します。
weeksは1を7日として計算します。

d = datetime.datetime(2020, 1, 1)
print(d - datetime.timedelta(days=1)) # -> 2019-12-31 00:00:00
print(d - datetime.timedelta(hours=2)) # -> 2019-12-31 22:00:00
print(d - datetime.timedelta(minutes=3)) # -> 2019-12-31 23:57:00
print(d - datetime.timedelta(seconds=4)) # -> 2019-12-31 23:59:56
print(d - datetime.timedelta(milliseconds=5)) # -> 2019-12-31 23:59:59.995000
print(d - datetime.timedelta(microseconds=6)) # -> 2019-12-31 23:59:59.999994
print(d - datetime.timedelta(weeks=7)) # -> 2019-11-13 00:00:00

日時の差分

datetimeオブジェクト同士の差分をとると、timedeltaが得られます。

d1 = datetime.datetime(2020, 1, 1)
d2 = datetime.datetime(2020, 10, 20, 9, 1, 2)
delta = d2 - d1
print(delta) # -> 293 days, 9:01:02

日時の比較

日時の新古を比較にするには、比較演算子で可能です。

d1 = datetime.datetime(2020, 1, 1)
d2 = datetime.datetime(2020, 10, 20, 9, 1, 2)
print(d1 > d2) # -> False
print(d1 >= d2) # -> False
print(d1 == d2) # -> False
print(d1 <= d2) # -> True
print(d1 < d2) # -> True

datetimeオブジェクトとdateオブジェクトの比較はできません。

日時から文字列へのフォーマット

日時から文字列へ変換してフォーマットするには、strftimeを使い、フォーマット形式を指定します。

d = datetime.datetime(2020, 10, 20, 9, 1, 2)
s = d.strftime("%Y/%m/%d %H:%M:%S")
print(s) # -> 2020/10/20 09:01:02

指定できる書式の詳細は公式ページをご覧ください。

文字列から日時への変換

文字列からdatetimeオブジェクトへ変換するには、strptimeを使います。
第一引数に変換元の文字列、第2引数に変換元文字列の書式を指定します。

s = "2020/10/20 09:01:02"
d = datetime.datetime.strptime(s, "%Y/%m/%d %H:%M:%S")
print(d) # -> 2020-10-20 09:01:02

こちらも指定できる書式は公式ページをご覧ください。

ライブラリの利用

標準で提供されている機能だけでは、プログラミングが複雑になる場合があります。
そんな時にライブラリを利用すると簡単に実装できることがあります。
今回は2つ紹介します。

dateutil

dateutilのrelativedeltaを使うと、timedeltaでは出来なかった、年や月の加減算ができます。

from dateutil.relativedelta import relativedelta

d = datetime.datetime(2020, 10, 20, 9, 1, 2)
print(d + relativedelta(months=1)) # -> 2020-11-20 09:01:02
print(d + relativedelta(years=1)) # -> 2021-10-20 09:01:02

print(d - relativedelta(months=1)) # -> 2020-09-20 09:01:02
print(d - relativedelta(years=1)) # -> 2019-10-20 09:01:02

arrow

arrowはJavaScriptのmement.jsに似たライブラリです。

d = arrow.get('2020-10-20T09:01:02')
print(d)
print(d.format("YYYY/MM/DD HH:mm:ss"))

日付操作には十分なテストが必要

日付と文字列を変換していると、環境によって時間が変わってしまうことがあります。

また、クライアントとサーバで日時をやり取りすると時間がが変わってしまうなどもあります。

こうした環境による時間の変化は、タイムゾーンが原因であることが考えられます。

実際のプロジェクトでは、データベースはどのタイムゾーンなのか、サーバはどのタイムゾーンで設定するのか、クライアントはどのタイムゾーンで表示するのかといったことを最初に決めておく必要があります。

これらを統一しておかないと、意図せず異なった日時で保存されてしまったり、間違った時間を元に処理が動いてしまったりといったことが発生します。

また、うるう年やうるう秒など、特定の時にだけ発生する時間差などもあります。

過去にもこうした対策がきちんと行われていないことが原因で、大きなトラブルになった事例もあります。

日付を扱う際には、実装時にも注意し、テストを十分に行うことをおすすめします。

今回はPythonの日付操作について紹介しました。

参考になれば幸いです。

コメント

タイトルとURLをコピーしました