日時

時間計測

時間計測には timeit モジュールまたは IPython の %timeit 機能が便利です:

%timeit x = 0; x = x + 1
14.7 ns ± 0.106 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)
%timeit x = 0; x += 1
16.1 ns ± 0.00604 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)

(あれ、x += 1 より x = x + 1 の方が若干速いんだ。)[2023-01-04 追記: M1 Mac mini 上の Python 3.11.1 で試したところ、どちらの時間も 12.3 ns ほどでした。]

ちなみに %%timeit とすると複数行の計測ができます(対話型環境では終了は空行を二つほど打つ):

%%timeit
x = 0
x += 1
15.7 ns ± 0.114 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)

%timeit の代わりに %time とすれば1回の時間を計測できます。

time

標準モジュール time はOSの機能に依存するようです。

time.time() は現在時刻を1970年元旦からの秒数(float 型)で返します。time.sleep() は指定した秒数(float 型)だけ休止します。

import time

t1 = time.time()
time.sleep(1.5)
t2 = time.time()
print(t2 - t1)

より精度の良い時間計測には time.perf_counter() を使います。こちらは差だけに意味があります。

t1 = time.perf_counter()
time.sleep(1.5)
t2 = time.perf_counter()
print(t2 - t1)

年月日時分秒で表した時刻:

time.localtime() # 現在時刻
time.localtime(t1)  # 1970年頭からの秒数t1の時刻
time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime()) # 'YYYY-MM-DD HH:MM:SS JST'
time.strftime('%Y-%m-%d %H:%M:%S %Z', time.gmtime())    # 'YYYY-MM-DD HH:MM:SS UTC'

ファイルのタイムスタンプ:

import os

p = os.stat("ファイルのパス")
time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime(p.st_mtime))

datetime

標準モジュール datetimetime と違ってOSに依存しません。

datetime.datetime 型は、年月日時分秒マイクロ秒を持つ構造体です:

import datetime

datetime.datetime.now()  # 現在時刻 datetime.datetime(年, 月, 日, 時, 分, 秒, μ秒)
datetime.datetime.now(datetime.timezone.utc)  # 同上(UTC)
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 'YYYY-MM-DD HH:MM:SS'
f'{datetime.datetime.now():%Y-%m-%d %H:%M:%S}' # 上と同じ

s = '2020-12-17 12:34:56'  # 現在時刻
t = datetime.datetime.strptime(s, '%Y-%m-%d %H:%M:%S')
t.timestamp()  # Epochからの秒数(sが現地時刻のとき)
t.replace(tzinfo=datetime.timezone.utc).timestamp() # sがUTCのとき

t1 = datetime.datetime.now()
# しばらく経って・・・
t2 = datetime.datetime.now()
t2 - t1     # datetime.timedelta(seconds=秒, microseconds=μ秒)
(t2 - t1).total_seconds()  # 秒単位

例えば2019年5月1日で始まる32日分の配列:

import numpy as np
import matplotlib.pyplot as plt

t = [datetime.datetime(2019,5,1) + datetime.timedelta(days=i) for i in range(32)]
rng = np.random.default_rng()
x = np.cumsum(rng.standard_normal(32))
plt.plot(t, x)
plt.xticks(rotation=20)
plt.show()

別の表示法:

import matplotlib.dates as mdates

fig, ax = plt.subplots()
locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
ax.plot(t, x)
plt.show()

dateutil

dateutil - powerful extensions to datetimepip install python-dateutil でインストールできます。

from dateutil.parser import parse

parse("1/6/21")
datetime.datetime(2021, 1, 6, 0, 0)
parse('Wed, 06 Jan 2021 12:54:19 +0900')
datetime.datetime(2021, 1, 6, 12, 54, 19, tzinfo=tzoffset(None, 32400))

NumPy

NumPy の datetime64 はとても柔軟な日時型です。年(Y)、月(M)、週(W)、日(D)、時(h)、分(m)、秒(s)、ミリ秒(ms)などの単位で64ビット整数で表したものです。日時の起点は1970年元旦です。タイムゾーンは考えません。一番大きい単位 Y を使った datetime64[Y] 型は ±9.2×1018 年まで表せます(宇宙の年齢は 1.38×1010 年ほど)。

import numpy as np

np.datetime64("2019")  # np.datetime64("2019", "Y") と同じ
np.datetime64("2019-05")  # np.datetime64("2019-05", "M") と同じ
np.datetime64("2019-05-01")  # np.datetime64("2019-05-01", "D") と同じ
np.datetime64("2019-05-01 12:34:56")  # np.datetime64("2019-05-01 12:34:56", "s") と同じ

日時の差は timedelta64() で表します:

t = np.array([np.datetime64("2019-05-01") + np.timedelta64(i,"D") for i in range(32)])

これは次のようにも書けます:

t = np.arange(np.datetime64("2019-05-01"), np.datetime64("2019-06-02"))

pandas

pandas の Timestamp は NumPy の datetime64[ns](ナノ秒単位)に限定しているので、1677-09-21(pd.Timestamp(-2**63+808))から2262-04-11(pd.Timestamp(2**63-1))くらいまでしか扱えません(データの読み書き参照)。

import pandas as pd

t = pd.to_datetime("2020-05-06")
t = pd.to_datetime("2020年5月6日", format='%Y年%m月%d日')  # 上と同じ
t                      #==> Timestamp('2020-05-06 00:00:00')
t.to_numpy()           #==> numpy.datetime64('2020-05-06T00:00:00.000000000')
t.to_pydatetime()      #==> datetime.datetime(2020, 5, 6, 0, 0)
t.timestamp()          #==> 1588723200.0  # seconds since Epoch
t.value                #==> 1588723200000000000  # ns since Epoch
t.strftime("%Y-%m-%d") #==> '2020-05-06'
t.year                 #==> 2020
t.month                #==> 5
t.day                  #==> 6
t.dayofweek            #==> 2  # 水曜日
t + pd.Timedelta(1, "D") #==> Timestamp('2020-05-07 00:00:00')

pd.to_datetime("2263-01-01") #==> TypeError OutOfBoundsDatetime
pd.to_datetime("2263-01-01", errors="coerce")  #==> NaT

a = pd.date_range("2020-01-01", "2020-01-03")
a    #==> DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03'],
                        dtype='datetime64[ns]', freq='D')
np.max(a)              #==> Timestamp('2020-01-03 00:00:00', freq='D')

format の形式については strftime() and strptime() Format Codes 参照。

Arrow

Arrow: Better dates & times for Python は新しい日時ライブラリです。pip install arrow でインストールできます。

Apache Arrow とは別物です。そちらの Python 版は PyArrow です。

import arrow

t1 = arrow.now()
t2 = arrow.utcnow()
print(t1, t2)
print(t2 - t1)
print((t2 - t1).total_seconds())
2022-08-10T10:15:28.009095+09:00 2022-08-10T01:15:28.009191+00:00
0:00:00.000096
9.6e-05
t = arrow.get("2022-08-10 00+09:00")
print(t)
print(t.timestamp())
print(t.format())
print(t.format("YYYY-MM-DD HH:mm:ss.SSS"))
2022-08-10T00:00:00+09:00
1660057200.0
2022-08-10 00:00:00+09:00
2022-08-10 00:00:00.000

その他

ファイルのタイムスタンプは次のようにして取得できます:

import os

p = os.stat("ファイル名")
print(f'{datetime.datetime.fromtimestamp(p.st_mtime):%Y-%m-%d %H:%M:%S}')