はじめに
numpyでの日付処理は速度を最優先にするためpandasやdatetimeと異なった形式で格納される。
https://numpy.org/doc/stable/reference/arrays.datetime.html
公式サイトを見るとわかる通り、Unix時間を単位[s or msなど]に応じて整数で格納される。
msの場合はUnix時間の秒数を1000倍にして整数にして格納する。
もちろんタイムゾーンもつけない。
numpy.datetime64に変換する際はタイムゾーンを外して行う必要がある。今のところエラーにはならないが、非推奨。
タイムゾーン付文字列(ISO 8601形式)からnumpy.datetime64に変換する
import datetime
import numpy as np
dateList = ['2021-01-01T12:00:00Z', '2021-01-02T12:00:00Z', '2021-07-02T12:00:00+09:00']
datetimeList = [datetime.datetime.fromisoformat(date).astimezone(tz=datetime.UTC).replace(tzinfo=None) for date in dateList]
datetimeList = np.array(datetimeList, dtype='datetime64[s]')
print(datetimeList) # ['2021-01-01T12:00:00' '2021-01-02T12:00:00' '2021-07-02T03:00:00']
このようにastimezone
メソッドを使用して使用するタイムゾーンに変換して、replace
メソッドを使用してタイムゾーンを外して変換する。
datatime.datetimeからnumpy.datetime64に変換する
上記の例に含まれるので割愛
numpy.datetime64からタイムゾーン付文字列(ISO 8601形式)に変換
import datetime
import time
import numpy as np
dateList = ['2021-01-01T12:00:00Z', '2021-01-02T12:00:00Z', '2021-07-02T12:00:00Z']
datetimeList = [datetime.datetime.fromisoformat(date).astimezone(tz=datetime.UTC).replace(tzinfo=None) for date in dateList]
datetimeList = np.array(datetimeList, dtype='datetime64[s]')
print(datetimeList) # ['2021-01-01T12:00:00' '2021-01-02T12:00:00' '2021-07-02T12:00:00']
# 方法1: numpy.datetime64[s]をstr関数で文字列化してZをつける
timeA = time.time()
for i in range(100000):
datetimeStrList = [str(datetime)+'Z' for datetime in datetimeList]
timeB = time.time()
print(timeB-timeA) # 0.2197432518005371
# 方法2: numpy.datetime64[s]を.astype('str')で文字列化してZをつける
timeA = time.time()
for i in range(100000):
datetimeStrList = [string+'Z' for string in datetimeList.astype('str')]
timeB = time.time()
print(timeB-timeA) # 0.4033396244049072
# 方法3: numpy.datetime64[s]を.astype(np.float64)でunix時間に変換し、datetimeにして文字列に直す。
timeA = time.time()
for i in range(100000):
strList = [datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC).strftime('%Y-%m-%dT%H:%M:%SZ')
for timestamp in datetimeList.astype(np.float64)]
timeB = time.time()
print(timeB-timeA) # 1.1203858852386475
方法2,3は配列の操作が2回発生し、時間がかかるので方法1で行うほうが良い。
方法3の場合はnumpy.datetime64[s]で格納されているものを使わないといけない。単位がmsだと値が1000倍違うためである。numpyのデフォルトの格納単位はmsなので特に注意が必要である。
numpy.datetime64からdatatime.datetimeに変換
import datetime
import numpy as np
dateList = ['2021-01-01T12:00:00Z', '2021-01-02T12:00:00Z', '2021-07-02T12:00:00Z']
datetimeList = [datetime.datetime.fromisoformat(date).astimezone(tz=datetime.UTC).replace(tzinfo=None) for date in dateList]
datetimeList = np.array(datetimeList, dtype='datetime64[s]')
print(datetimeList) # ['2021-01-01T12:00:00' '2021-01-02T12:00:00' '2021-07-02T12:00:00']
datetimeList = [datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC) for timestamp in datetimeList.astype(np.float64)]
print(datetimeList)
datetimeList.astype(np.float64)
により、整数のみ(ここではUNIX時間)を抜き出す。それからdatetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)
によりdatetime.datetime
に変換する。タイムゾーンをつけたい場合はtzに必要なタイムゾーンを入れ、つけない場合はNoneにする。
ここでもnumpy.datetime64[s]で格納されているか注意する。そうでなければいったん変換する。
参考
公式サイト