Pythonでファイルのタイムスタンプ(作成日時や更新日時)を取得
Pythonでファイルの作成日時や更新日時などのタイムスタンプを取得するには、標準ライブラリのosモジュールやpathlibモジュールを使う。取得できるのはUNIX時間(エポック秒)だが、datetimeモジュールを使って日時(日付と時刻)に変換することも可能。
以下のタイムスタンプが取得できる。OSによって意味合いが異なるので特に作成日時については注意が必要。本記事のサンプルコードはmacOSで実行している。
- atime: 最終アクセス日時
- mtime: 最終内容更新日時
- ctime: メタデータの最終更新日時(UNIX) / 作成日時(Windows)
- birthtime: 作成日時(macOSを含むFreeBSD系の一部のUNIXのみ)
pathlibモジュールの基本的な使い方については以下の記事を参照。
本記事のサンプルコードでは、以下のようにファイルを作成し10秒後に更新した状態を例とする。以降で使用するモジュールもまとめてインポートしている。
import os
import pathlib
import datetime
import time
import platform
p = pathlib.Path('data/temp/test.txt')
p.write_text('test')
time.sleep(10)
p.write_text('update')
タイムスタンプ情報を持つos.stat_resultを取得
タイムスタンプなどのファイルのメタデータはos.stat_result
オブジェクトの属性として取得できる。
os.stat_result
はPath.stat()
またはos.stat()
で取得できる。
Path.stat()
pathlib.Path
オブジェクトのstat()
メソッドでos.stat_result
オブジェクトを取得できる。
print(p.stat())
# os.stat_result(st_mode=33188, st_ino=8728494137, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=6, st_atime=1549094615, st_mtime=1549094615, st_ctime=1549094615)
print(type(p.stat()))
# <class 'os.stat_result'>
os.stat()
osモジュールのos.stat()
関数でもos.stat_result
オブジェクトを取得できる。引数はパス文字列かpathlib.Path
オブジェクト。
print(os.stat('data/temp/test.txt'))
# os.stat_result(st_mode=33188, st_ino=8728494137, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=6, st_atime=1549094615, st_mtime=1549094615, st_ctime=1549094615)
print(type(os.stat('data/temp/test.txt')))
# <class 'os.stat_result'>
print(os.stat(p))
# os.stat_result(st_mode=33188, st_ino=8728494137, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=6, st_atime=1549094615, st_mtime=1549094615, st_ctime=1549094615)
print(type(os.stat(p)))
# <class 'os.stat_result'>
どの方法でも同じ値のos.stat_result
オブジェクトが得られる。
print(p.stat() == os.stat('data/temp/test.txt') == os.stat(p))
# True
os.stat_resultの属性
os.stat_result
オブジェクトの属性st_atime
, st_mtime
, st_ctime
でタイムスタンプが取得できる。また、macOSを含むFreeBSD系の一部のUNIXシステムではst_birthtime
という属性もある。それぞれの意味については後述。
st = p.stat()
print(st.st_atime)
# 1549094615.972488
print(st.st_mtime)
# 1549094615.9723485
print(st.st_ctime)
# 1549094615.9723485
print(st.st_birthtime)
# 1549094605.9650702
いずれの属性も浮動小数点数float
でUNIX時間(エポック秒)を表す。日時データdatetime
に変換する方法については後述。
print(type(st.st_ctime))
# <class 'float'>
st_atime_ns
, st_ctime_ns
, st_mtime_ns
というナノ秒単位の値を整数int
で格納する属性もある。st_birthtime
には相当する属性はない。
print(st.st_ctime_ns)
# 1549094615972348510
print(type(st.st_ctime_ns))
# <class 'int'>
なお、公式ドキュメントにあるように、浮動小数点数float
で小数点以下の情報を含んでいたり、xxx_ns
でナノ秒単位の値を格納したりしているが、その精度が担保されているものではないので注意。
注釈:
st_atime
、st_mtime
、およびst_ctime
属性の厳密な意味や精度はオペレーティングシステムやファイルシステムによって変わります。例えば、 FAT や FAT32 ファイルシステムを使用している Windows システムでは、st_mtime
の精度は 2 秒であり、st_atime
の精度は 1 日に過ぎません。詳しくはお使いのオペレーティングシステムのドキュメントを参照してください。 os --- 雑多なオペレーティングシステムインターフェース — Python 3.10.12 ドキュメント
os.stat_result
にはそのほかにもバイト単位のサイズを示すst_size
などの属性もある。ファイルやフォルダのサイズの取得については以下の記事を参照。
os.pathの関数でタイムスタンプを取得
タイムスタンプはos.path
の関数、getatime()
, getmtime()
, getctime()
で取得することも可能。
print(os.path.getatime('data/temp/test.txt'))
# 1549094615.972488
print(os.path.getmtime('data/temp/test.txt'))
# 1549094615.9723485
print(os.path.getctime('data/temp/test.txt'))
# 1549094615.9723485
パス文字列ではなくpathlib.Path
オブジェクトも引数に指定できる。
print(os.path.getctime(p))
# 1549094615.9723485
ソースコードを見ると分かるように、これらの関数の内部ではos.stat_result
の対応する属性を取得しているだけ。
def getmtime(filename):
"""Return the last modification time of a file, reported by os.stat()."""
return os.stat(filename).st_mtime
def getatime(filename):
"""Return the last access time of a file, reported by os.stat()."""
return os.stat(filename).st_atime
def getctime(filename):
"""Return the metadata change time of a file, reported by os.stat()."""
return os.stat(filename).st_ctime
当然ながら上述のPath.stat()
やos.stat()
でos.stat_result
を取得しその属性を指定する方法とまったく同じ値が得られる。
print(os.path.getctime(p) == p.stat().st_ctime)
# True
st_atime_ns
, st_ctime_ns
, st_mtime_ns
およびst_birthtime
を取得する関数は用意されていない。
タイムスタンプを日時datetimeに変換
これまでの例のように、os.stat_result
などで得られるタイムスタンプはUNIX時間(エポック秒)で表されている。
UNIX時間を日時を表すdatetime
オブジェクトに変換するにはdatetimeモジュールのdatetime.fromtimestamp()
関数を使う。
dt = datetime.datetime.fromtimestamp(p.stat().st_ctime)
print(dt)
# 2019-02-02 17:03:35.972348
print(type(dt))
# <class 'datetime.datetime'>
変換時にタイムゾーンを指定する方法など詳細は以下の記事を参照。
datetime
オブジェクトは任意のフォーマットやISOフォーマットの文字列に変換できる。
print(dt.strftime('%Y年%m月%d日 %H:%M:%S'))
# 2019年02月02日 17:03:35
print(dt.isoformat())
# 2019-02-02T17:03:35.972348
タイムスタンプの種類: atime, ctime, mtime, birthtime
冒頭に述べたようにタイムスタンプにはatime, ctime, mtime, birthtimeがある。
- atime: 最終アクセス日時
- mtime: 最終内容更新日時
- ctime: メタデータの最終更新日時(UNIX) / 作成日時(Windows)
- birthtime: 作成日時(macOSを含むFreeBSD系の一部のUNIXのみ)
詳細は以下のページを参照。
UNIXにおける定義については以下のページが詳しく分かりやすかった。
更新日時を取得
いわゆる更新日時という意味ではOSによらずmtimeを取得すればよい。
os.stat_result
のst_mtime
属性かos.path.getmtime()
関数を使う。
print(os.path.getmtime('data/temp/test.txt'))
# 1549094615.9723485
print(p.stat().st_mtime)
# 1549094615.9723485
datetime
オブジェクトに変換するにはdatetimeモジュールのdatetime.fromtimestamp()
関数を使う。
print(datetime.datetime.fromtimestamp(p.stat().st_mtime))
# 2019-02-02 17:03:35.972348
UNIXにおいてはctimeでメタデータの最終更新時刻が取得できるので、例えばファイル名の変更なども検知したい場合はmtimeではなくctimeを使う(Windowsではctimeは作成日時なので注意)。
作成日時を取得
上述のように作成日時の取得方法はOSによって異なる。
- Windows: ctime
- macOSなど一部のUNIX: birthtime
- それ以外のUNIX: 作成日時は取得できない(少なくともPython3.11時点では)
クロスプラットフォームな方法
Windowsのみ、あるいは、macOSのみで使用するプログラムであればst_ctime
やst_birthtime
を使えばいいが、マルチプラットフォームに対応させたい場合は対応が必要。
Stack Overflowの以下の質問および回答で挙げられているサンプルコードを引用する。
def creation_date(path_to_file):
"""
Try to get the date that a file was created, falling back to when it was
last modified if that isn't possible.
See http://stackoverflow.com/a/39501288/1709587 for explanation.
"""
if platform.system() == 'Windows':
return os.path.getctime(path_to_file)
else:
stat = os.stat(path_to_file)
try:
return stat.st_birthtime
except AttributeError:
# We're probably on Linux. No easy way to get creation dates here,
# so we'll settle for when its content was last modified.
return stat.st_mtime
platform.system()
でWindowsか判定し、さらに例外処理を利用してst_birthtime
属性が存在する場合とそれ以外で処理を切り替えている。platform.system()
および例外処理についての詳細は以下の記事を参照。
使用例は以下の通り。引数はパス文字列かpathlib.Path
オブジェクト。
print(creation_date(p))
# 1549094605.9650702
print(datetime.datetime.fromtimestamp(creation_date(p)))
# 2019-02-02 17:03:25.965070
なお、このサンプルコードでは、st_birthtime
が存在しないOSでは更新日時を示すst_mtime
を返していることに注意。場合によってはNone
などを返すようにして作成日時を取得できないことを明確に示すほうがよいかもしれない。