Pythonで、datetimeモジュールを使う

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

Python - 標準ライブラリ
2018年11月22日21:21に更新(約21日前)
2018年11月14日18:46に作成(約29日前)

旧ブログ移行記事です。

Pythonで日付・時刻を扱うときは、標準ライブラリにあるdatetimeモジュールを使います。標準ライブラリには他にtime(datetime.timeのことじゃないよ)calendarといったモジュールもあるのですが、基本的にはこのdatetimeモジュールを使うことになります。

datetimeモジュールでは、主に3つの種類のオブジェクトを扱います。

  • 日付と時間を表現するdatetime.datetime
  • 日付を表現するdatetime.date
  • 時間を表現するdatetime.time

日付・時刻を扱うdatetime.datetime

以下では、datetime.datetime型のオブジェクトを作成しています。

import datetime

dt = datetime.datetime(year=2017, month=12, day=30, hour=12, minute=0, second=30)

実際のところ、上のコードはdatetimeモジュールのdatetimeクラスをインスタンス化しているだけです。

現在の日付・時刻を表すdatetime.datetimeオブジェクトが欲しいならば以下のように簡単に書けます。now()ですね。

import datetime

now = datetime.datetime.now()

datetime.datetimeオブジェクト...他のdatetimeもそうですが、日付・時刻の加算・減産であったり、文字列⇔datetime.datetimeの相互変換、タイムゾーンのサポート、等など様々な機能を持っています。

公式ドキュメントに、端的な説明がありましたので抜粋します。

datetime モジュールでは、日付や時間データを簡単な方法と複雑な方法の両方で操作するためのクラスを提供しています。日付や時刻を対象にした四則演算がサポートされている一方で、このモジュールの実装では出力の書式化や操作を目的とした属性の効率的な取り出しに焦点を絞っています

便利な機能を色々紹介する前に、datetime.datedatetime.time も簡単に紹介していきます。

日付を扱うdatetime.date

時間が必要ない場合...日付だけで良い場合は、datetime.dateが使えます。datetime.datetimeから、時間に関するものを抜いたオブジェクトです。

datetime.date型のオブジェクトを作るには、datetimeと同様にインスタンス化します。

import datetime

day = datetime.date(year=2017, month=12, day=30)

today()で今日の日付を表すオブジェクトが作れます。

import datetime

today = datetime.date.today()

時間を扱うdatetime.time

時間だけで良い場合は、datetime.timeが使えます。datetime.datetimeから、日付に関するものを抜いたものと考えましょう。

import datetime

time = datetime.time(hour=10, minute=30, second=0)

日付・時刻を文字列に変換する

datetime.datetime等のオブジェクトをprint関数に渡すと、それなりには表示がされます。

import datetime

now = datetime.datetime.now()
print(now)
2018-11-14 19:21:56.142769

もう少しカッコよく表示させたり、文字列として変換させたい場合も多くあります。

strftimeを使う

datetime, date, timeオブジェクトそれぞれにstrftime()があります。

import datetime

now = datetime.datetime.now()
now_str = now.strftime('%Y/%m/%d %H:%M:%S')
print(now_str)

ちゃんと整形されていますね。

2018/11/14 19:28:44

%Yは年、%mは月...のように対応しています。どの文字がどの部分に対応するかの詳細は、公式ドキュメントをご覧ください。

Python標準の機能を使う

formatといった、標準的な書式操作でも扱うことができます。strftimeになれない方は、こちらの方が使いやすいかもしれません。

import datetime

now = datetime.datetime.now()
now_str1 = '{0.year}年{0.month}月{0.day}日 {0.hour}時{0.minute}分{0.second}秒'.format(now)
now_str2 = f'{now.year}年{now.month}月{now.day}日'
now_str3 = '%s年%s月%s日' % (now.year, now.month, now.day)
print(now_str1)
print(now_str2)
print(now_str3)
2018年11月14日 19時37分27秒
2018年11月14日
2018年11月14日

datetimeの各オブジェクトにはyear, month, day, hour, minute, dayといった属性がありますので、単純にそれを取り出して文字列にしています。なんとなくわかるとおもいますが、datetime.dateにはhour等の属性はありませんし、datetime.timeにはyear等の属性はありません。datetime.datetimeは全て持っています。

文字列をdatetimeオブジェクトに変換する

上の逆として、文字列からdatetime.datetime等に変換することもできます。これは実際よく使う機能です。

以下は、'2017/12/31 20:00:30'という文字列をdatetime.datetimeオブジェクトに変換しています。

import datetime

dt_str = '2017/12/31 20:00:30'
dt = datetime.datetime.strptime(dt_str, '%Y/%m/%d %H:%M:%S')

以下のコードは'2017/12/31'という文字列から変換します。時間を指定しないでdatetime.datetimeオブジェクトに変換した場合は、時間は0:00:00になります。

import datetime

dt_str = '2017/12/31'
dt = datetime.datetime.strptime(dt_str, '%Y/%m/%d')

strptime()の第二引数は、文字列のどこが年月日、時間に対応しているかを教えるための指定です。元の文字列とズレがある場合はエラーになります。

例えばですが、以下のコードは元の文字列の20:00:30の部分が解釈できなくてエラーです。

import datetime

dt_str = '2017/12/31 20:00:30'  # 20:00:30部分が余分!
dt = datetime.datetime.strptime(dt_str, '%Y/%m/%d')
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    dt = datetime.datetime.strptime(dt_str, '%Y/%m/%d')
  File "c:\python37\Lib\_strptime.py", line 577, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "c:\python37\Lib\_strptime.py", line 362, in _strptime
    data_string[found.end():])
ValueError: unconverted data remains:  20:00:30

以下のコードは、書式の%H:%M:%Sに対応する部分が元の文字列にないのでエラーです。

import datetime

dt_str = '2017/12/31'  # %H:%M:%S 部分がない!
dt = datetime.datetime.strptime(dt_str, '%Y/%m/%d %H:%M:%S')
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    dt = datetime.datetime.strptime(dt_str, '%Y/%m/%d %H:%M:%S')
  File "c:\python37\Lib\_strptime.py", line 577, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "c:\python37\Lib\_strptime.py", line 359, in _strptime
    (data_string, format))
ValueError: time data '2017/12/31' does not match format '%Y/%m/%d %H:%M:%S'

元の文字列と指定した書式にズレがないか、よく確認するようにしましょう。

補足として、strptime()datetime.datetimeにしかありません。datetime.date, datetime.time型のオブジェクトが欲しい場合は、下で紹介するdatetime型をdate型、time型に変換するをご覧ください。

datetime型をdate型、time型に変換する

datetime.datetimeオブジェクトの、date()を呼び出すとdate型に変換されます。

import datetime

dt_str = '2017/12/31'
date = datetime.datetime.strptime(dt_str, '%Y/%m/%d').date()

time()を呼び出すとtime型に変換されます。

import datetime

dt_str = '2017/12/31'
time = datetime.datetime.strptime(dt_str, '%Y/%m/%d').time()

date型とtime型を合体させてdatetime型にする

dateとtimeからdatetimeを作りたい場合は、datetime.datetime.combine()を使います。

import datetime

time = datetime.time(hour=10, minute=30, second=15)
date = datetime.date.today()  # todayで、現在の日付
dt = datetime.datetime.combine(date, time)

日付・時刻の加算減算

数日後や数時間前といった、日付・時刻の加算減算も簡単に行えます。

以下のコードは、現在日付の3日後のdatetime.datetimeオブジェクトを作成します。

import datetime

dt_now = datetime.datetime.now()
delta_3 = datetime.timedelta(days=3)  # 3日の差分
after_3_days = dt_now + delta_3  # 3日後

日付・時刻の加算減算にはdatetime.timedeltaオブジェクトを使います。このオブジェクトは、日付や時刻の差分を表しているオブジェクトです。

この差分をdatetime.datetime等のオブジェクトに足したり引いたりすることでn日後、n日前といったことができます。上のコードならば、3日の差分現在の日付に足すことで3日後ということですね。

n日前としたいならば、days=-3のように負の値を指定しても良いですし、dt_now - delta_3のように-演算子を使っても良いです。

timedelta()の引数はweeks, days, hours, minutes, seconds, milliseconds, microsecondsがあり、好きに指定できます。引数名が複数形なことと、年、月単位の指定はできないことに注意してください。

1年は365~366、月は28~31までブレがあるためです。年や月の増減をしたい場合はよく使うイディオム的なものをご覧ください。

よく使うイディオム的なもの

私が個人的によく使うイディオム的なものをまとめました。

ある日付から1週間後までのリストを作成する

import datetime

base_date = datetime.datetime.now()
datetime_list = [base_date + datetime.timedelta(days=day) for day in range(7)]

# 見やすく表示したかった
from pprint import pprint;pprint(datetime_list)

よくできていますね!

[datetime.datetime(2018, 11, 15, 0, 5, 44, 725421),
 datetime.datetime(2018, 11, 16, 0, 5, 44, 725421),
 datetime.datetime(2018, 11, 17, 0, 5, 44, 725421),
 datetime.datetime(2018, 11, 18, 0, 5, 44, 725421),
 datetime.datetime(2018, 11, 19, 0, 5, 44, 725421),
 datetime.datetime(2018, 11, 20, 0, 5, 44, 725421),
 datetime.datetime(2018, 11, 21, 0, 5, 44, 725421)]

n月後を求める

11月15日から1月後は、一般的に12月15日です。12月25日ならば、1月後は1月25ですし、1月前は11月25です。

更に、1月31日から1月後ならば2月31...はないので、2月28又は2月29、そんな月の増減がしたいとします。そういった処理がしたい場合は以下のように書けます。

import calendar
import datetime


def add_month(base_date, months):
    """月の増減を行う"""
    month = base_date.month - 1 + months
    year = int(base_date.year + month / 12 )
    month = month % 12 + 1
    day = min(base_date.day,calendar.monthrange(year,month)[1])
    return datetime.date(year,month,day)


dt = datetime.datetime(year=2018, month=1, day=31)
print(add_month(dt, 1))
print(add_month(dt, -1))
print(add_month(dt, 10))
2018-02-28
2017-12-31
2018-11-30

datetimeの差を求める

2つのdatetime.datetimeを受け取り、その差を○時間○分と返すようなシンプルな処理であれば以下のように書けます。実を言うと、datetime.datetime同士であれば単純に加算・減産できます(戻り値はdatetime.timedelta)。

import datetime


def get_diff_time(dt1, dt2):
    """1時間30分 のように、2つのdatetimeの差を返す"""
    td = dt2 - dt1
    return '{0}時間{1}分'.format(
        td.seconds // 3600, (td.seconds // 60) % 60)


dt1 = datetime.datetime(year=2017, month=12, day=23, hour=10)
dt2 = datetime.datetime(year=2017, month=12, day=23, hour=12, minute=30)
print(get_diff_time(dt1, dt2))  # 2時間30分

Djangoで、何時間ログインしたかを調べるのに使いました。

今から〇分前、〇時間前、〇日前

twitter等でよく見かける、n時間前n日前、といった、現在からの差を表したいとします。

import datetime


def by_the_time(dt):
    """その時間が今からどのぐらい前か、人にやさしい表現で返す."""
    result = datetime.datetime.now() - dt
    s = result.total_seconds()
    hours = int(s / 3600)
    if hours >= 24:
        day = int(hours / 24)
        return '約{0}日前'.format(day)
    elif hours == 0:
        minute = int(s / 60)
        return '約{0}分前'.format(minute)
    else:
        return '約{0}時間前'.format(hours)


# 今は2018/11/15 0:25です。
dt1 = datetime.datetime(year=2018, month=11, day=15, hour=0)
dt2 = datetime.datetime(year=2018, month=11, day=14, hour=22)
dt3 = datetime.datetime(year=2018, month=11, day=10)

print(by_the_time(dt1))
print(by_the_time(dt2))
print(by_the_time(dt3))
約25分前
約2時間前
約5日前

このブログでも使っている処理です。

タイムゾーン関連

Pythonで、pytzを使ったタイムゾーンの変換をご覧ください。

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

記事にコメントする