- Python で日付データを扱いたい
- 日付から別の型への変換がしたい
- 日付型に苦手意識がある
他の型と比べるとやや分かりづらいのが「日付型」です。
それもそのはず、ひとくちに日付型といっても以下の複合的な要因で成り立っています。
- 「年」「月」「日」などの複数要素から成り立つ
- 地球上には時差があるので、測定する場所で時間は異なる
- 色々な型変換の方法がある
そのため、初見では理解しづらいテーマです。
本記事では、そんな日付型の操作に必要な知識を Python 初心者の方でも理解できるように網羅的に扱いました。
Python で日時を扱うための基礎知識
まずは日付型を理解するために知っておくと便利な予備知識から解説します。
日付を扱うライブラリ
基本的には以下のモジュールを使うことになります。
- datetime
- time
- calendar
ただし、少し複雑な集計などを行う場合には Pandas ライブラリを使うと便利です。
Pandas の方が少ないコードで複雑な実装ができますし、C言語で最適化されているので動作も超高速です。
Pandas について詳しく知りたい方は別記事をどうぞ。
» 業務系アプリケーションで Pandas を活用する方法
タイムゾーン
地球上には時差があるので、どの場所を基準にするかによって現在時刻は異なります。
この「どこを基準にした時間かを記録する」ものがタイムゾーンです。
ここで覚えておくと便利な用語が、Aware と Naive です。
Aware がタイムゾーンを含んだ日時オブジェクト、 Naive がタイムゾーンを含まない日時オブジェクトを指します。
以下のようにタイムゾーンに関する指定をせずに日付取得する場合は、タイムゾーン情報なしの値が取得されます。つまり、Naive なオブジェクトが取得されます。
import datetime
now = datetime.datetime.now()
timezone = now.tzinfo
# [timezone]
# None
Aware なタイムゾーン付きの日付オブジェクトを取得する場合には、以下のように timezone() メソッドなどを使って場所に関する情報を付与してあげることになります。
import datetime
# タイムゾーン = UTC にセット
now_utc = datetime.datetime.now(datetime.timezone.utc)
timezone_utc = now_utc.tzinfo
# [timezone_utc]
# UTC
# <class 'datetime.timezone'>
# タイムゾーン = 日本にセット
jst = datetime.timezone(datetime.timedelta(hours=9))
now_jst = datetime.datetime.now(jst)
timezone_jst = now_jst.tzinfo
# [timezone_jst]
# UTC+09:00
# <class 'datetime.timezone'>
上記で timedelta(hours=9) としている理由は、日本は UTC から9時間の時差があるためです。
ただしすべての時差をぱっと見で理解するのはそこそこ大変だと思いますので、これらの情報があらかじめ記録された pytz ライブラリで実現するとより簡潔に記述できます。
imoprt pytz
import datetime
# タイムゾーン = Asia/Tokyo にセット
jst = pytz.timezone("Asia/Tokyo")
now_jst = datetime.datetime.now(jst)
timezone_jst = now_jst.tzinfo
# [timezone_jst]
# Asia/Tokyo
# <class 'pytz.tzfile.Asia/Tokyo'>
時差を直接指定するよりも、Asia/Tokyo とした方が視覚的に分かりやすいでしょう。
現在の日時を取得
ログをはじめ、現在の日時を出力したいシチュエーションはかなり多いと思います。
日付だけ、時間だけといったバリエーションも含めて、取得方法をご紹介します。
現在日時の取得
日時情報を丸ごと取得したい場合は datetime() メソッドを使います。
import datetime
now = datetime.datetime.now()
# [now]
# 2023-10-14 22:08:25.355012
# <class 'datetime.datetime'>
現在日付の取得
「年月日」部分だけを取得したい場合には、today() メソッドを使います。
import datetime
today = datetime.date.today()
# [today]
# 2023-10-14
# <class 'datetime.date'>
現在時刻の取得
「時間」部分だけを取得したい場合は、まずdatetime.now() で日時を求めた後に time() メソッドで時間部分だけを切り出します。
import datetime
now_time = datetime.datetime.now().time()
# [now_time]
# 22:53:17.458025
# <class 'datetime.time'>
現在のエポック秒(UNIX 時間)を取得
UTC(協定世界時)からの経過秒数をエポック秒といいます。
具体的には1970年1月1日0時0分0秒からの経過時間です。
import time
unix_time = time.time()
# [unix_time]
# 1697325018.0934207
# <class 'float'>
特定の日時データを取得する
日時データからより細かい情報を取得する方法をご紹介します。
ある月の日数を取得する
monthrange() メソッドを使うと、タプルの形式で (月の初日の曜日, 月の日数)
という形で戻り値が得られます。
import calendar
# 2023年10月の初日の曜日と、日数
days_of_week, days = calendar.monthrange(2023, 10)
# [days_of_week]
# 6
# [days]
# 31
上記のようにアンパッキングしてそれぞれの変数に、各値を入れると便利です。
なお曜日は月曜日を0、日曜日を6とする値になります。
日数だけ取得したい場合は以下のように書けます。
import calendar
# 2023年10月の日数
_, days = calendar.monthrange(2023, 10)
# [days]
# 31
もちろん、calendar.monthrange(2023, 10)[1]
のような書き方でも OK です。
日付から曜日を取得する
weekday() メソッドを使うことで、曜日を表す数値が得られます。
import datetime
now = datetime.datetime.now()
weekday = now.weekday()
# [now]
# 2023-10-17 09:58:04.530179
# <class 'datetime.datetime'>
# [weekday]
# 1
# <class 'int'>
なお曜日は月曜日を0、日曜日を6とする値になります。
【timedelta】時間どうしの差分から計算する
時間どうしの差分を計算したい場合には timedelta を使いましょう。
timedelta を使った時間の足し算・引き算
以下が timedelta() メソッドを使った時間の足し算の方法です。
from datetime import datetime, timedelta
# 現在日時を取得
now = datetime.now()
# 現在日時から時間を足し算する
tomorrow = now + timedelta(
# 1週間後
weeks=1,
# 1日後
days=1,
# 1時間後
hours=1,
# 1分後
minutes=1,
# 1秒後
seconds=1,
# 1マイクロ秒後
microseconds=1,
# ミリ秒後
milliseconds=1,
)
上記では説明のためにすべての属性を使いましたが、値を0としたい場合には属性を省略すれば大丈夫です。
例えば、単に現在から1日後の日付型を取得したいなら以下でいけます。
from datetime import datetime, timedelta
# 現在日時を取得
now = datetime.now()
# 現在日時から1日後を取得
tomorrow = now + timedelta(days=1)
引き算の場合にはマイナス(-
)を指定します。
from datetime import datetime, timedelta
# 現在日時を取得
now = datetime.now()
# 現在日時から1日前を取得
tomorrow = now - timedelta(days=1)
上記では- timedelta()
としましたが、+ timedelta(days=-1)
としても結果は同じです。どちらか可読性の高い方を採用すべきと思います。
relativedelta を使った時間の足し算・引き算
簡単な時間の足し算・引き算は timedelta() で十分ですが、月単位・年単位の時間の足し算・引き算は relativedelta() を使うのが簡単です。
from datetime import datetime
from dateutil.relativedelta import relativedelta
# 現在日時を取得
now = datetime.now()
# 2ヶ月後の日付
two_months_later = now + relativedelta(months=+2)
このdatiutil は標準ライブラリではないので、pip 等でインストールしておく必要があります。
pip install python-dateutil
datetime 型オブジェクトの変換
datetime オブジェクトは他の形式に変換することも可能です。
datetime 型から str 型に変換する方法
datetime 型から str 型に変換する方法は、strftime() メソッドを使う方法と属性名で呼び出す方法の二つがあります。
strftime() メソッドを使う方法
「2023年10月14日」のように、複数の属性の組み合わせで取得したい場合には strftime() メソッドを使います。
属性とは年、月、時間などの各要素のことです。
import datetime
now = datetime.datetime.now()
ymd = now.strftime("%Y年%m月%d日")
# [ ymd ]
# 2023年10月14日
# <class 'str'>
ymdhms = now.strftime("%Y年%m月%d日 %H:%M:%S")
# [ ymdhms ]
# 2023年10月14日 22:16:02
# <class 'str'>
どの属性を使って文字列にするかは、書式コードというものを使います。
どんな書式コードがあるかについては公式ドキュメントに網羅されているので、必要に応じて参照しつつコードを完成させてみてください。
» 公式ドキュメント:strftime() と strptime() の書式コード
属性名で呼び出す方法
日付だけを抽出したい場合など、一つの属性だけが必要な場合には.属性名
とすることで int 型で取得できます。
以下は指定できる属性のすべてになります。
import datetime
now = datetime.datetime.now()
now.year
# [ now.year ]
# 2023
# <class 'int'>
now.month
# [ now.month ]
# 10
# <class 'int'>
now.day
# [ now.day ]
# 14
# <class 'int'>
now.hour
# [ now.hour ]
# 22
# <class 'int'>
now.minute
# [ now.minute ]
# 37
# <class 'int'>
now.second
# [ now.second ]
# 7
# <class 'int'>
now.microsecond
# [ now.microsecond ]
# 691433
# <class 'int'>
datetime オブジェクトの判定
判定系のメソッドをまとめました。
うるう年の判定
calendar モジュールを使うことで簡単に判定ができます。
import calendar
is_leap_2020 = calendar.isleap(2020)
# [ is_leap_2020 ]
# True
is_leap_2023 = calendar.isleap(2023)
# [ is_leap_2023 ]
# False
上記の関数を使えば気にする必要はないですが、うるう年かどうかの判定ロジックは以下のように求められます。
Wikipedia: グレゴリオ暦
calendar モジュールを使いたくない場合は、自作の関数で対応することもできます。
def is_leap_year(target_year: int):
"""うるう年か判定"""
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
return True
else:
return False
コメント