RustPython/RustPython · error · TypeError

time argument must be a time instance

Error message

time argument must be a time instance

What it means

The second half of datetime.combine's contract: the time argument must be a time instance (a datetime does not qualify — pass dt.time()). Passing a string like '09:00', a tuple, or None raises TypeError naming the time argument, since combine reads .hour/.minute/.second/.microsecond/.fold directly.

Source

Thrown at Lib/_pydatetime.py:1910

    def utcnow(cls):
        "Construct a UTC datetime from time.time()."
        import warnings
        warnings.warn("datetime.datetime.utcnow() is deprecated and scheduled for "
                      "removal in a future version. Use timezone-aware "
                      "objects to represent datetimes in UTC: "
                      "datetime.datetime.now(datetime.UTC).",
                      DeprecationWarning,
                      stacklevel=2)
        t = _time.time()
        return cls._fromtimestamp(t, True, None)

    @classmethod
    def combine(cls, date, time, tzinfo=True):
        "Construct a datetime from a given date and a given time."
        if not isinstance(date, _date_class):
            raise TypeError("date argument must be a date instance")
        if not isinstance(time, _time_class):
            raise TypeError("time argument must be a time instance")
        if tzinfo is True:
            tzinfo = time.tzinfo
        return cls(date.year, date.month, date.day,
                   time.hour, time.minute, time.second, time.microsecond,
                   tzinfo, fold=time.fold)

    @classmethod
    def fromisoformat(cls, date_string):
        """Construct a datetime from a string in one of the ISO 8601 formats."""
        if not isinstance(date_string, str):
            raise TypeError('fromisoformat: argument must be str')

        if len(date_string) < 7:
            raise ValueError(f'Invalid isoformat string: {date_string!r}')

        # Split this at the separator
        try:
            separator_location = _find_isoformat_datetime_separator(date_string)

View on GitHub (pinned to aaeab4f754)

Solutions

  1. Parse first: datetime.combine(d, time.fromisoformat('09:00')) or time(9, 0).
  2. When the source value is a datetime, pass value.time() to combine.
  3. Type-check the second argument (isinstance(t, time)) before calling.
  4. Validate config schema so time fields arrive as time objects or known strings.

Example fix

// before
dt = datetime.combine(day, cfg['alarm'])  # cfg['alarm'] == '09:00'

// after
from datetime import time
alarm = time.fromisoformat(cfg['alarm']) if isinstance(cfg['alarm'], str) else cfg['alarm']
dt = datetime.combine(day, alarm)
Defensive patterns

Strategy: type-guard

Validate before calling

from datetime import time

def coerce_time_arg(t):
    if isinstance(t, str):
        return time.fromisoformat(t)
    if not isinstance(t, time):
        raise TypeError(f'time argument must be a time instance, got {type(t).__name__}')
    return t

Type guard

from datetime import datetime, time

def is_time_instance(v) -> bool:
    return isinstance(v, time) and not isinstance(v, datetime)

Try / catch

try:
    dt = datetime.combine(d, t)
except TypeError as e:
    if 'time argument' in str(e):
        dt = datetime.combine(d, t.time() if isinstance(t, datetime) else time.fromisoformat(t))
    else:
        raise

Prevention

When it happens

Trigger: datetime.combine(date.today(), '09:00'); passing (9, 30) tuples from config; passing a datetime where a time is expected (use dt.time()); a None default leaking through from optional config.

Common situations: Alarm/scheduling config holding human-readable strings; row tuples from databases mapped positionally; refactors that changed a variable from time to str.

Related errors


AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17). Data as JSON: /api/errors/906abe8cbd93a71e. Report an issue: GitHub.