note.nkmk.me

Pythonでファイルのタイムスタンプ(作成日時や更新日時)を取得

Date: 2019-02-02 / tags: Python

Pythonでファイルの作成日時や更新日時といったタイムスタンプを取得するには、標準ライブラリのosモジュールやpathlibモジュールを使う。取得できるのはUNIX時間(エポック秒)だが、datetimeモジュールを使って日時(日付と時刻)に変換することも可能。

以下のタイムスタンプが取得できる。OSによって意味合いが異なるので特に作成日時については注意が必要。

  • atime: 最終アクセス日時
  • mtime: 最終内容更新日時
  • ctime: メタデータの最終更新日時(UNIX) / 作成日時(Windows)
  • birthtime: 作成日時(macOSを含むFreeBSD系の一部のUNIXのみ)

ここでは以下の内容について説明する。

  • os.stat_resultを取得
    • Path.stat()
    • os.stat()
    • os.stat_resultの属性
  • os.pathの関数で取得
  • タイムスタンプを日時datetimeに変換
  • タイムスタンプの種類: atime, ctime, mtime, birthtime
  • 更新日時を取得
  • 作成日時を取得
    • クロスプラットフォームな方法

以下のようにファイルを作成し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')
source: os_stat.py

なお、pathlibモジュールはPython3.4で追加されたのでそれより前のバージョンでは使えない。また、os.stat()などosモジュールの関数の引数にパスの文字列ではなくpathlib.Pathオブジェクトなどのいわゆるpath-like objectを指定できるようになったのはPython3.6から。

pathlibモジュールの基本的な使い方については以下の記事を参照。

スポンサーリンク

os.stat_resultを取得

タイムスタンプなどのファイルのメタデータはos.stat_resultオブジェクトの属性として取得できる。

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'>
source: os_stat.py

os.stat()

osモジュールのos.stat()関数でもos.stat_resultオブジェクトを取得できる。引数はパス文字列かpathlib.Pathオブジェクト(Python3.6以降)。

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'>
source: os_stat.py

どの方法でも同じ値のos.stat_resultオブジェクトが得られる。

print(p.stat() == os.stat('data/temp/test.txt') == os.stat(p))
# True
source: os_stat.py

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
source: os_stat.py

いずれの属性も浮動小数点数float型でUNIX時間(エポック秒)を表す。この値を日時データdatetimeに変換する方法については後述。

print(type(st.st_ctime))
# <class 'float'>
source: os_stat.py

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'>
source: os_stat.py

なお、公式ドキュメントにあるように、浮動小数点数floatで小数点以下の情報を含んでいたり、xxx_nsでナノ秒単位の値を格納したりしているが、その精度が担保されているものではないので注意。

st_atime 、 st_mtime 、および st_ctime 属性の厳密な意味や精度はオペレーティングシステムやファイルシステムによって変わります。例えば、 FAT や FAT32 ファイルシステムを使用している Windows システムでは、 st_mtime の精度は 2 秒であり、 st_atime の精度は 1 日に過ぎません。詳しくはお使いのオペレーティングシステムのドキュメントを参照してください。
os.stat_result --- 雑多なオペレーティングシステムインタフェース — Python 3.7.2 ドキュメント

os.stat_resultにはそのほかにもバイト単位のサイズを示すst_sizeなど様々な属性がある。

ファイルやフォルダのサイズの取得については以下の記事を参照。

os.pathの関数で取得

タイムスタンプはos.pathの関数で取得することも可能。

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
source: os_stat.py

Python3.6以降はパス文字列ではなくpathlib.Pathオブジェクトを引数に指定してもOK。

print(os.path.getctime(p))
# 1549094615.9723485
source: os_stat.py

ソースコードを見ると分かるように、これらの関数の内部では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
source: os_stat.py

st_atime_ns, st_ctime_ns, st_mtime_nsおよびst_birthtimeを取得する関数は用意されていない。

タイムスタンプを日時datetimeに変換

これまでのサンプルコードのように、タイムスタンプは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'>
source: os_stat.py

変換時にタイムゾーンを指定する方法など詳細は以下の記事を参照。

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
source: os_stat.py

それぞれの詳細については以下の記事を参照。

タイムスタンプの種類: atime, ctime, mtime, birthtime

冒頭に述べたようにタイムスタンプにはatime, ctime, mtime, birthtimeがある。

  • atime: 最終アクセス日時
  • mtime: 最終内容更新日時
  • ctime: メタデータの最終更新日時(UNIX) / 作成日時(Windows)
  • birthtime: 作成日時(macOSを含むFreeBSD系の一部のUNIXのみ)

詳細は以下のページを参照。

UNIXにおける定義については以下のページが詳しく分かりやすかった。

更新日時を取得

いわゆる更新日時という意味ではOSによらずmtimeを取得すればよい。

これまでのサンプルコードのように、os.stat_resultst_mtime属性かos.path.getmtime()関数を使う。

print(os.path.getmtime('data/temp/test.txt'))
# 1549094615.9723485

print(p.stat().st_mtime)
# 1549094615.9723485
source: os_stat.py

datetimeオブジェクトに変換するにはdatetimeモジュールのdatetime.fromtimestamp()関数を使う。

print(datetime.datetime.fromtimestamp(p.stat().st_mtime))
# 2019-02-02 17:03:35.972348
source: os_stat.py

UNIXにおいてはctimeでメタデータの最終更新時刻が取得できるので、例えばファイル名の変更なども検知したい場合はmtimeではなくctimeを使う(Windowsではctimeは作成日時なので注意)。

作成日時を取得

上述のように作成日時の取得方法はOSによって異なる。

  • Windows: ctime
  • macOSなど一部のUNIX: birthtime
  • それ以外のUNIX: 作成日時は取得できない(少なくともPython3.7時点では)

クロスプラットフォームな方法

Windowsのみ、あるいは、macOSのみで使用するプログラムであればst_ctimest_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
source: os_stat.py

まずplatform.system()の値でWindowsかそれ以外かを判定し、さらに例外処理を利用してst_birthtime属性が存在する場合とそれ以外で処理を切り替えている。platform.system()および例外処理についての詳細は以下の記事を参照。

使用例は以下の通り。引数はパス文字列かpathlib.Pathオブジェクト(Python3.6以降)。

print(creation_date(p))
# 1549094605.9650702

print(datetime.datetime.fromtimestamp(creation_date(p)))
# 2019-02-02 17:03:25.965070
source: os_stat.py

なお、このサンプルコードでは、st_birthtimeが存在しないOSでは更新日時を示すst_mtimeを返していることに注意。場合によってはNoneなどを返すようにして作成日時を取得できないことを明確に示すほうがよいかもしれない。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事