プロジェクト

全般

プロフィール

操作

第8章 日付と時刻の処理

8.1 日付や時刻を扱う datetime

datetime モジュールのオブジェクト

オブジェクト名 用途
date 日付
time 時刻
datetime 日時
timedelta 2つの日時の差
  • date オブジェクト

    • date(year, month, day)

    • インスタンスメソッド

      メソッド名 解説 戻り値
      weekday() 曜日を返す (月曜日 0, 日曜日 6) int
      isoweekday() 曜日を返す (月曜日 1, 日曜日 7) int
      isoformat() ISO 8601形式 (YYYY-MM-DD) で表した文字列を返す str
      strftime(format) 指定したフォーマットに従って日付文字列を返す str
    • 属性

      属性名 解説 戻り値
      year int
      month int
      day int
    • クラスメソッド

      メソッド名 解説 戻り値
      today() 今日の日付の date オブジェクトを返す datetime.date
      fromisoformat(date_string) ISO 8601形式 (YYYY-MM-DD) で表した日付文字列から date オブジェクトを生成する datetime.date
    >>> from datetime import date
    >>> today = date.today()
    >>> today
    datetime.date(2025, 7, 2)
    >>> birthday = date(1983, 9, 28)
    >>> birthday
    datetime.date(1983, 9, 28)
    >>> today.isoweekday()
    3
    >>> today.isoformat()
    '2025-07-02'
    >>> tomorrow = date.fromisoformat('2025-07-03')
    >>> tomorrow.day
    3
    >>> tomorrow.isoweekday()
    4
    >>> tomorrow.strftime("明日は西暦 %Y 年 %m 月 %d 日 (%a) です")
    '明日は西暦 2025 年 07 月 03 日 (Thu) です'
    
  • time オブジェクト

    • time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)

    • インスタンスメソッド

      メソッド名 解説 戻り値
      isoformat(timespec='auto') ISO 8601 形式 (HH:MM:SS.ffffff) の文字列を返す
      マイクロ秒が 0 の場合は HH:MM:SS
      (*1)
      str
      strftime(format) (略) str
      tzname() タイムゾーン名 str
      • (*1) timespec : 大きいほうからどこまで表示するかを指定する (非表示部分は切り捨て)
        • hours HH
        • minutes HH:MM
        • seconds HH:MM:SS
        • milliseconds HH:MM:SS.sss
        • microseconds HH:MM:SS.mmmmmm
        • auto : microsecond が 0 なら seconds 、そうでない場合 microseconds
    • 属性

      属性名 解説 戻り値
      hour int
      minute int
      second int
      microsecond マイクロ秒 int
      tzinfo タイムゾーン情報 オブジェクト
      fold (略) 0 または 1 int
    • クラスメソッド

      メソッド名 解説 戻り値
      fromisoformat(time_string) ISO 8601 形式 (HH:MM:SS.ffffff または HH:MM:SS) の文字列から time オブジェクトを生成 datetime.time
    >>> from datetime import time
    >>> t1 = time.fromisoformat("21:54:12.345678")
    >>> t1
    datetime.time(21, 54, 12, 345678)
    >>> t1.isoformat()
    '21:54:12.345678'
    >>> t1.hour
    21
    >>> t1.second
    12
    >>> t1.strftime("今は %H 時 %M 分 %S 秒 です")
    '今は 21 時 54 分 12 秒 です'
    
  • datetime オブジェクト

    • datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)

    • インスタンスメソッド

      メソッド名 解説 戻り値
      date() 同じ年月日の date を返す datetime.date
      time() 同じ時分秒の time を返す datetime.time
      isoformat(sep='T', timespec='auto') sep は 1 文字で、日付と時刻の間に配置される
      他は date, time の同メソッド参照
      str
      strftime(format) (略) str
      tzname() (略) str
    • 属性

      • date, time と同じ
      • year month day hour minute second microsecond tzinfo fold
    • クラスメソッド

      メソッド名 解説 戻り値
      today() デフォルトタイムゾーンの現在日時を表す datetime を返す
      ※「today」だが、時刻も設定される
      datetime.datetime
      now(tz=None) today() と同様だが、tz に zoneinfo.ZoneInfo オブジェクトを渡せばタイムゾーンを指定可能 datetime.datetime
      utcnow() UTC の現在日時を表す datetime を返す datetime.datetime
      fromisoformat(date_string) ISO 8601 形式 (YYYY-MM-DDTHH:MM:SS.ffffff) の文字列から datetime を生成 datetime.datetime
      strptime(date_string, format) 指定したフォーマットに従って文字列から datetime オブジェクトを生成 datetime.datetime
  • timedelta オブジェクト
    date, time, datetime の差を扱うオブジェクト

    • timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
    • date, time, datetime の差演算結果は timedelta オブジェクトとして返る
    from datetime import date, timedelta
    >>> today = date.today()
    >>> today
    datetime.date(2025, 7, 2)
    >>> birthday = date(1983, 9, 28)
    >>> delta = today - birthday
    >>> delta.days / 365
    41.78904109589041
    
  • strftime() での指定子
    代表的なもの

    指定子 意味 使用例
    %d 0 埋めした月中の日にち 01,02,...,31
    %m 0 埋めした月 01,02,...,12
    %y 0 埋めした西暦下2桁 00,01,...,99
    %Y 0 埋めした西暦4桁 0001,0002,...,9999
    %H 0 埋めした時 (24時間表記) 00,01,...,23
    %M 0 埋めした分 00,01,...,59
    %S 0 埋めした秒 00,01,...,59
  • パースエラー

    • fromisoformat() strptime() でパースできない文字列を渡すと、ValueError が発生する

8.2 時刻を扱う time

time モジュールはエポック (epoch) という基準時刻からの経過時間 (エポック秒) を扱う. 通常エポックは 1970年1月1日0時0分0秒

  • 主な関数

    関数名 解説 戻り値
    gmtime([secs]) UTC の現在時刻を表す struct_time を返す
    secs が指定された場合はエポック秒 secs として扱う
    time.struct_time
    localtime([secs]) ローカルの現在時刻を表す struct_time を返す
    secs が指定された場合はエポック秒 secs として扱う
    time.struct_time
    strftime(format[, t]) t(time.struct_time) を指定されたフォーマットに従った文字列として返す
    t が指定されない場合は localtime() の値を使用
    str
    time() エポックからの秒数を返す float
    >>> import time
    >>> time.gmtime()
    time.struct_time(tm_year=2025, tm_mon=7, tm_mday=2, tm_hour=14, tm_min=13, tm_sec=21, tm_wday=2, tm_yday=183, tm_isdst=0)
    >>> time.localtime()
    time.struct_time(tm_year=2025, tm_mon=7, tm_mday=2, tm_hour=23, tm_min=13, tm_sec=30, tm_wday=2, tm_yday=183, tm_isdst=0)
    >>> time.strftime("日本は %H:%M:%S")
    '日本は 23:14:34'
    >>> time.time()
    1751465685.0863643
    
  • 時刻オブジェクト struct_time

    • struct_time は名前付きタプル
    インデックス 属性名 解説 戻り値
    0 tm_year int
    1 tm_mon int
    2 tm_mday int
    3 tm_hour int
    4 tm_min int
    5 tm_sec int
    6 tm_wday 曜日 (0:月曜日) int
    7 tm_yday 年の中での日 (1 - 366) int
    8 tm_isdst 夏時間かどうか (0:夏時間ではない) int
    tm_zone タイムゾーン名 str
    tm_gmtoff タイムゾーンの UTC からのオフセット秒 int
    >>> jtime = time.localtime()
    >>> jtime
    time.struct_time(tm_year=2025, tm_mon=7, tm_mday=2, tm_hour=23, tm_min=16, tm_sec=33, tm_wday=2, tm_yday=183, tm_isdst=0)
    >>> jtime[0]
    2025
    >>> jtime.tm_hour
    23
    >>> jtime.tm_sec
    33
    
  • スレッドの一時停止 sleep()

  • time モジュール使用例

    • 処理失敗時のリトライ時に sleep() で待機
    • datetime と組み合わせて日時計算
    • 計測対象の処理前後で現在時刻取得をして、簡易処理時間計測
  • time.sleep() と async/await 構文は意図通りに動作しない可能性あり

    • async/await は 19.1 (p.446)

8.3 IANA タイムゾーンデータベースを扱う zoneinfo

  • ZoneInfo オブジェクト
    • ZoneInfo(key)
      • key タイムゾーン名
      >>> from zoneinfo import ZoneInfo
      >>> TOKYO = ZoneInfo('Asia/Tokyo')
      Traceback (most recent call last):
        File "C:\Python313\Lib\zoneinfo\_common.py", line 12, in load_tzdata
          return resources.files(package_name).joinpath(resource_name).open("rb")
                 ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
        File "C:\Python313\Lib\importlib\resources\_common.py", line 46, in wrapper
          return func(anchor)
        File "C:\Python313\Lib\importlib\resources\_common.py", line 56, in files
          return from_package(resolve(anchor))
                              ~~~~~~~^^^^^^^^
        File "C:\Python313\Lib\functools.py", line 934, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
        File "C:\Python313\Lib\importlib\resources\_common.py", line 82, in _
          return importlib.import_module(cand)
                 ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
        File "C:\Python313\Lib\importlib\__init__.py", line 88, in import_module
          return _bootstrap._gcd_import(name[level:], package, level)
                 ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
        File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
        File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
        File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
        File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
        File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
        File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
        File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
        File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
        File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
        File "<frozen importlib._bootstrap>", line 1324, in _find_and_load_unlocked
      ModuleNotFoundError: No module named 'tzdata'
      
      During handling of the above exception, another exception occurred:
      
      Traceback (most recent call last):
        File "<python-input-1>", line 1, in <module>
          TOKYO = ZoneInfo('Asia/Tokyo')
        File "C:\Python313\Lib\zoneinfo\_common.py", line 24, in load_tzdata
          raise ZoneInfoNotFoundError(f"No time zone found with key {key}")
      zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key Asia/Tokyo'
      
      • Windows では上記の様にエラーが出る (OS の タイムゾーンデータベースの形式が TZif でない為)
        • tzdata パッケージをインストールすれば解決する
        • pip install tzdata
        >>> from zoneinfo import ZoneInfo
        >>> TOKYO = ZoneInfo('Asia/Tokyo')
        >>> TOKYO
        zoneinfo.ZoneInfo(key='Asia/Tokyo')
        >>> from datetime import datetime
        >>> dt = datetime(1983, 9, 28, tzinfo=TOKYO)
        >>> dt
        datetime.datetime(1983, 9, 28, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
        >>> dt.astimezone(ZoneInfo('America/Los_Angeles')
        ... )
        datetime.datetime(1983, 9, 27, 8, 0, tzinfo=zoneinfo.ZoneInfo(key='America/Los_Angeles'))
        

8.4 datetime の強力な拡張モジュール dateutil

  • インストール
    • pip install python-dateutil

日付文字列の構文解析 parser

  • parser.parse(timestr, parserinfo=None, **kwargs) (戻り値: datetime.datetime)

    • timestr 日時文字列
    • parserinfo 日付解析の振る舞いを変更するためのオブジェクト
    • **kwargs
      • default 変換するときのデフォルト値となる datetime オブジェクト
      • dayfirst True を指定すると "1/2/3" などの先頭を「日」として解析する
      • yearfirst True を指定すると "1/2/3" などの先頭を「年」として解析する
    >>> from dateutil.parser import parse
    >>> parse("2025/7/3 21:54")
    datetime.datetime(2025, 7, 3, 21, 54)
    >>> parse("1/2/3")
    datetime.datetime(2003, 1, 2, 0, 0)  # 指定無しは 月/日/年 と解析
    >>> parse("1/2/3", dayfirst=True)  
    datetime.datetime(2003, 2, 1, 0, 0)  # 日/月/年 と解析
    >>> parse("1/2/3", yearfirst=True)
    datetime.datetime(2001, 2, 3, 0, 0)  # 年/月/日 と解析
    >>> from datetime import datetime
    >>> default_dt = datetime.today()
    >>> default_dt
    datetime.datetime(2025, 7, 3, 21, 57, 47, 441323)  # デフォルトを 2025-07-03 21:57:47 とする
    >>> parse("12:30:55", default=default_dt)
    datetime.datetime(2025, 7, 3, 12, 30, 55)  # 文字列に無い値はデフォルトの値になる
    

日付の差の計算 relativedelta

  • relativedelta.relativedelta(引数下記)

    • date または datetime を 2 つ渡すと、その差を relativedelta として生成
      • dt1=None
      • dt2=None
    • 相対値引数 : 和差演算の際に、増減させる値を指定 (数値の前に + - を付加)
      • years=0
      • months=0
      • days=0
      • leapdays=0
      • weeks=0
      • hours=0
      • minutes=0
      • seconds=0
      • microseconds=0
    • 絶対値引数 : 和差演算の際に、ここで指定した値に置換する (増減ではない)
      • year=None
      • month=None
      • day=None
      • weekday=None
      • yearday=None
      • nlyearday=None
      • hour=None
      • minute=None
      • second=None
      • microsecond=None
    >>> from datetime import datetime, date
    >>> from dateutil.relativedelta import relativedelta
    >>> today = date.today()
    >>> today
    datetime.date(2025, 7, 3)
    >>> birthday = date(1983, 9, 28)
    >>> birthday
    datetime.date(1983, 9, 28)
    >>> relativedelta(today, birthday)            # 今日と誕生日の差を relativedelta で
    relativedelta(years=+41, months=+9, days=+5)  # 41年9か月と5日
    >>> now = datetime.now()
    >>> now
    datetime.datetime(2025, 7, 3, 22, 28, 37, 209118)    # 2025-07-03 22:28:37
    >>> now + relativedelta(days=+3, hours=+1)           # 3日と1時間後
    datetime.datetime(2025, 7, 6, 23, 28, 37, 209118)    # 2025-07-06 23:28:37
    >>> now + relativedelta(months=+4, day=20)           # 4か月後の20日
    datetime.datetime(2025, 11, 20, 22, 28, 37, 209118)  # 2025-11-20 22:28:37
    >>> now - relativedelta(months=+8, day=20)           # 8か月前の20日
    datetime.datetime(2024, 11, 20, 22, 28, 37, 209118)  # 2024-11-20 22:28:37
    
    >>> from datetime import datetime, date
    >>> from dateutil.relativedelta import relativedelta
    >>> from dateutil.relativedelta import MO, TU, WE, TH, FR, SA, SU
    >>> today = date.today()
    >>> today
    datetime.date(2025, 7, 3)
    >>> today + relativedelta(weekday=SU)  # 次の日曜日
    datetime.date(2025, 7, 6)
    >>> today + relativedelta(weekday=SU(-1))  # 前の日曜日
    datetime.date(2025, 6, 29)
    >>> today + relativedelta(yearday=365)  # 年の365日目
    datetime.date(2025, 12, 31)
    >>> today + relativedelta(months=+2, day=1, weekday=SA(+3))  # 2か月後の3回目の土曜日
    datetime.date(2025, 9, 20)
    

繰り返しルール rrule

  • rrule.rrule(引数下記)

    • freq 繰り返し頻度 YEARLY MONTHLY WEEKLY DAILY HOURLY MINUTELY SECONDLY
    • cache=False True の場合キャッシュする
    • dtstart=None 開始日時を datetime で指定、指定無しの場合は datetime.now() の値が使われる
    • interval=1 間を飛ばす数 (例:HOURLY で interval=2 なら、2時間毎)
    • wkst=None 週の始まりの曜日 (byweekno を指定した場合に意味を持つようだ)
    • count=None 繰り返し回数 (until と同時には指定できない)
    • until=None 終了日時を datetime で指定 (count と同時には指定できない)
    • bysetpos=None byXXXX で指定したルールに対して、何回目のものを有効とするかを + - の数値で指定
    • bymonth bymonthday byweekno byweekday byhour byminute bysecond byeaster 指定された期間のみを対象とする (フィルタのようなもの). 単一値、またはタプルを指定
      • 特定月、特定日(毎月25日等)、特定曜日(月曜と木曜等)、特定番号週(年の週番号指定の週) など
    >>> from dateutil.rrule import rrule
    >>> from dateutil.rrule import DAILY, WEEKLY, MONTHLY
    >>> from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
    >>> import pprint
    >>> import sys
    >>> sys.displayhook = pprint.pprint  # 表示を見やすくするために設定
    >>> start = datetime(2021, 2, 16)
    >>> list(rrule(DAILY, count=3, dtstart=start))  # 指定日から3日間
    [datetime.datetime(2021, 2, 16, 0, 0),
     datetime.datetime(2021, 2, 17, 0, 0),
     datetime.datetime(2021, 2, 18, 0, 0)]
    >>> list(rrule(DAILY, dtstart=start, until=datetime(2021, 2, 19)))  # 指定期間毎日
    [datetime.datetime(2021, 2, 16, 0, 0),
     datetime.datetime(2021, 2, 17, 0, 0),
     datetime.datetime(2021, 2, 18, 0, 0),
     datetime.datetime(2021, 2, 19, 0, 0)]
    >>> list(rrule(WEEKLY, count=4, wkst=SU, byweekday=(TU,TH), dtstart=start))  # 毎週火曜、木曜
    [datetime.datetime(2021, 2, 16, 0, 0),
     datetime.datetime(2021, 2, 18, 0, 0),
     datetime.datetime(2021, 2, 23, 0, 0),
     datetime.datetime(2021, 2, 25, 0, 0)]
    >>> list(rrule(MONTHLY, count=3, byweekday=FR(-1), dtstart=start))  # 毎月最終金曜日
    [datetime.datetime(2021, 2, 26, 0, 0),
     datetime.datetime(2021, 3, 26, 0, 0),
     datetime.datetime(2021, 4, 30, 0, 0)]
    

Tatsuya ISHIGAKI さんが5ヶ月前に更新 · 1件の履歴