Skip to content

Time

An object representing a time.

Internally, the time is computed in ticks; there are 254016000000 ticks per second [Premiere Scripting Guide Time object].

Source code in src/py_premiere/models/time.py
class Time:
    """An object representing a time.

    Internally, the time is computed in `ticks`; there are 254016000000
    ticks per second [Premiere Scripting Guide `Time` object].
    """

    def __init__(self, ticks: int = 0) -> None:
        self.ticks = ticks

    @property
    def ticks(self) -> int:
        """The time value, expressed in ticks. Read/write."""
        return self._ticks

    @ticks.setter
    def ticks(self, value: int) -> None:
        validate_int(value)
        self._ticks = value

    @property
    def seconds(self) -> float:
        """The time value, expressed in seconds. Read/write."""
        return self._ticks / TICKS_PER_SECOND

    @seconds.setter
    def seconds(self, value: float) -> None:
        validate_number(value)
        ticks = value * TICKS_PER_SECOND
        if not math.isfinite(ticks):
            # A finite number of seconds can still overflow to infinity once
            # scaled by the tick rate; `round` would raise OverflowError.
            raise ValueError(f"{value} seconds is too large to express in ticks")
        self._ticks = round(ticks)

    @classmethod
    def from_seconds(cls, seconds: float) -> Time:
        """A `Time` from a number of seconds, rounded to the nearest tick."""
        time = cls()
        time.seconds = seconds
        return time

    @classmethod
    def from_frames(cls, frames: int, timebase: Time | int) -> Time:
        """A `Time` from a frame count.

        `timebase` is ticks per frame (the unit `FrameRate` elements and
        `Sequence.timebase` use), given as an int or a `Time`.
        """
        validate_int(frames)
        return cls(frames * _timebase_ticks(timebase))

    def to_frames(self, timebase: Time | int) -> int:
        """The frame this time falls in (floored to a whole frame)."""
        return self._ticks // _timebase_ticks(timebase)

    @classmethod
    def from_timecode(cls, timecode: str, timebase: Time | int) -> Time:
        """A `Time` from a `HH:MM:SS:FF` timecode string.

        A `;` before the frame field (`01:00:00;02`) marks drop-frame,
        which only exists for the 29.97/59.94 family.
        """
        _validate_timecode_string(timecode)
        drop = ";" in timecode
        parts = timecode.replace(";", ":").split(":")
        if len(parts) != 4 or not all(part.isdigit() for part in parts):
            raise ValueError(f"not a HH:MM:SS:FF timecode: {timecode!r}")
        hours, minutes, seconds, frames = (int(part) for part in parts)
        ticks = _timebase_ticks(timebase)
        nominal = _nominal_fps(ticks)
        if minutes >= 60 or seconds >= 60 or frames >= nominal:
            raise ValueError(f"timecode field out of range: {timecode!r}")
        number = ((hours * 60 + minutes) * 60 + seconds) * nominal + frames
        if drop:
            dropped = _drop_count(ticks)
            total_minutes = hours * 60 + minutes
            if seconds == 0 and minutes % 10 and frames < dropped:
                # The first frame numbers of a dropped minute do not exist.
                raise ValueError(f"dropped frame number: {timecode!r}")
            number -= dropped * (total_minutes - total_minutes // 10)
        return cls(number * ticks)

    def to_timecode(self, timebase: Time | int, drop_frame: bool = False) -> str:
        """This time as a `HH:MM:SS:FF` string (floored to a whole frame).

        With `drop_frame`, counts in drop-frame and separates the frame
        field with `;`, as Premiere displays 29.97/59.94 material.
        """
        ticks = _timebase_ticks(timebase)
        if self._ticks < 0:
            raise ValueError("cannot format a negative time as timecode")
        number = self._ticks // ticks
        nominal = _nominal_fps(ticks)
        if drop_frame:
            dropped = _drop_count(ticks)
            per_ten_minutes = nominal * 600 - dropped * 9
            per_minute = nominal * 60 - dropped
            tens, rest = divmod(number, per_ten_minutes)
            if rest > dropped:
                number += dropped * 9 * tens + dropped * (
                    (rest - dropped) // per_minute
                )
            else:
                number += dropped * 9 * tens
        seconds_total, frames = divmod(number, nominal)
        minutes_total, seconds = divmod(seconds_total, 60)
        hours, minutes = divmod(minutes_total, 60)
        separator = ";" if drop_frame else ":"
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}{separator}{frames:02d}"

    def __eq__(self, other: object) -> bool:
        # No paired __hash__: `ticks` is writable, and mutating a Time held
        # in a set or used as a dict key would corrupt the container, so
        # defining `__eq__` alone deliberately leaves the class unhashable.
        if not isinstance(other, Time):
            return NotImplemented
        return self._ticks == other._ticks

    def __repr__(self) -> str:
        return f"Time(ticks={self._ticks})"

    def __add__(self, other: object) -> Time:
        if not isinstance(other, Time):
            return NotImplemented
        return Time(self._ticks + other._ticks)

    def __sub__(self, other: object) -> Time:
        if not isinstance(other, Time):
            return NotImplemented
        return Time(self._ticks - other._ticks)

    def __mul__(self, other: object) -> Time:
        if not isinstance(other, (int, float)):
            return NotImplemented
        return Time(round(self._ticks * other))

    __rmul__ = __mul__

    def __floordiv__(self, other: object) -> Time:
        # int only: `int // float` yields a float the ticks setter rejects;
        # timedelta refuses float floor-division for the same reason.
        if not isinstance(other, int):
            return NotImplemented
        return Time(self._ticks // other)

    def __truediv__(self, other: object) -> Time:
        if not isinstance(other, (int, float)):
            return NotImplemented
        return Time(round(self._ticks / other))

    def __neg__(self) -> Time:
        return Time(-self._ticks)

    def __abs__(self) -> Time:
        return Time(abs(self._ticks))

    def __lt__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._ticks < other._ticks

    def __le__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._ticks <= other._ticks

    def __gt__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._ticks > other._ticks

    def __ge__(self, other: object) -> bool:
        if not isinstance(other, Time):
            return NotImplemented
        return self._ticks >= other._ticks

Attributes

__rmul__ class-attribute instance-attribute

__rmul__ = __mul__

seconds property writable

seconds

The time value, expressed in seconds. Read/write.

ticks property writable

ticks

The time value, expressed in ticks. Read/write.

Methods:

__abs__

__abs__()
Source code in src/py_premiere/models/time.py
def __abs__(self) -> Time:
    return Time(abs(self._ticks))

__add__

__add__(other)
Source code in src/py_premiere/models/time.py
def __add__(self, other: object) -> Time:
    if not isinstance(other, Time):
        return NotImplemented
    return Time(self._ticks + other._ticks)

__eq__

__eq__(other)
Source code in src/py_premiere/models/time.py
def __eq__(self, other: object) -> bool:
    # No paired __hash__: `ticks` is writable, and mutating a Time held
    # in a set or used as a dict key would corrupt the container, so
    # defining `__eq__` alone deliberately leaves the class unhashable.
    if not isinstance(other, Time):
        return NotImplemented
    return self._ticks == other._ticks

__floordiv__

__floordiv__(other)
Source code in src/py_premiere/models/time.py
def __floordiv__(self, other: object) -> Time:
    # int only: `int // float` yields a float the ticks setter rejects;
    # timedelta refuses float floor-division for the same reason.
    if not isinstance(other, int):
        return NotImplemented
    return Time(self._ticks // other)

__ge__

__ge__(other)
Source code in src/py_premiere/models/time.py
def __ge__(self, other: object) -> bool:
    if not isinstance(other, Time):
        return NotImplemented
    return self._ticks >= other._ticks

__gt__

__gt__(other)
Source code in src/py_premiere/models/time.py
def __gt__(self, other: object) -> bool:
    if not isinstance(other, Time):
        return NotImplemented
    return self._ticks > other._ticks

__init__

__init__(ticks=0)
Source code in src/py_premiere/models/time.py
def __init__(self, ticks: int = 0) -> None:
    self.ticks = ticks

__le__

__le__(other)
Source code in src/py_premiere/models/time.py
def __le__(self, other: object) -> bool:
    if not isinstance(other, Time):
        return NotImplemented
    return self._ticks <= other._ticks

__lt__

__lt__(other)
Source code in src/py_premiere/models/time.py
def __lt__(self, other: object) -> bool:
    if not isinstance(other, Time):
        return NotImplemented
    return self._ticks < other._ticks

__mul__

__mul__(other)
Source code in src/py_premiere/models/time.py
def __mul__(self, other: object) -> Time:
    if not isinstance(other, (int, float)):
        return NotImplemented
    return Time(round(self._ticks * other))

__neg__

__neg__()
Source code in src/py_premiere/models/time.py
def __neg__(self) -> Time:
    return Time(-self._ticks)

__repr__

__repr__()
Source code in src/py_premiere/models/time.py
def __repr__(self) -> str:
    return f"Time(ticks={self._ticks})"

__sub__

__sub__(other)
Source code in src/py_premiere/models/time.py
def __sub__(self, other: object) -> Time:
    if not isinstance(other, Time):
        return NotImplemented
    return Time(self._ticks - other._ticks)

__truediv__

__truediv__(other)
Source code in src/py_premiere/models/time.py
def __truediv__(self, other: object) -> Time:
    if not isinstance(other, (int, float)):
        return NotImplemented
    return Time(round(self._ticks / other))

from_frames classmethod

from_frames(frames, timebase)

A Time from a frame count.

timebase is ticks per frame (the unit FrameRate elements and Sequence.timebase use), given as an int or a Time.

Source code in src/py_premiere/models/time.py
@classmethod
def from_frames(cls, frames: int, timebase: Time | int) -> Time:
    """A `Time` from a frame count.

    `timebase` is ticks per frame (the unit `FrameRate` elements and
    `Sequence.timebase` use), given as an int or a `Time`.
    """
    validate_int(frames)
    return cls(frames * _timebase_ticks(timebase))

from_seconds classmethod

from_seconds(seconds)

A Time from a number of seconds, rounded to the nearest tick.

Source code in src/py_premiere/models/time.py
@classmethod
def from_seconds(cls, seconds: float) -> Time:
    """A `Time` from a number of seconds, rounded to the nearest tick."""
    time = cls()
    time.seconds = seconds
    return time

from_timecode classmethod

from_timecode(timecode, timebase)

A Time from a HH:MM:SS:FF timecode string.

A ; before the frame field (01:00:00;02) marks drop-frame, which only exists for the 29.97/59.94 family.

Source code in src/py_premiere/models/time.py
@classmethod
def from_timecode(cls, timecode: str, timebase: Time | int) -> Time:
    """A `Time` from a `HH:MM:SS:FF` timecode string.

    A `;` before the frame field (`01:00:00;02`) marks drop-frame,
    which only exists for the 29.97/59.94 family.
    """
    _validate_timecode_string(timecode)
    drop = ";" in timecode
    parts = timecode.replace(";", ":").split(":")
    if len(parts) != 4 or not all(part.isdigit() for part in parts):
        raise ValueError(f"not a HH:MM:SS:FF timecode: {timecode!r}")
    hours, minutes, seconds, frames = (int(part) for part in parts)
    ticks = _timebase_ticks(timebase)
    nominal = _nominal_fps(ticks)
    if minutes >= 60 or seconds >= 60 or frames >= nominal:
        raise ValueError(f"timecode field out of range: {timecode!r}")
    number = ((hours * 60 + minutes) * 60 + seconds) * nominal + frames
    if drop:
        dropped = _drop_count(ticks)
        total_minutes = hours * 60 + minutes
        if seconds == 0 and minutes % 10 and frames < dropped:
            # The first frame numbers of a dropped minute do not exist.
            raise ValueError(f"dropped frame number: {timecode!r}")
        number -= dropped * (total_minutes - total_minutes // 10)
    return cls(number * ticks)

to_frames

to_frames(timebase)

The frame this time falls in (floored to a whole frame).

Source code in src/py_premiere/models/time.py
def to_frames(self, timebase: Time | int) -> int:
    """The frame this time falls in (floored to a whole frame)."""
    return self._ticks // _timebase_ticks(timebase)

to_timecode

to_timecode(timebase, drop_frame=False)

This time as a HH:MM:SS:FF string (floored to a whole frame).

With drop_frame, counts in drop-frame and separates the frame field with ;, as Premiere displays 29.97/59.94 material.

Source code in src/py_premiere/models/time.py
def to_timecode(self, timebase: Time | int, drop_frame: bool = False) -> str:
    """This time as a `HH:MM:SS:FF` string (floored to a whole frame).

    With `drop_frame`, counts in drop-frame and separates the frame
    field with `;`, as Premiere displays 29.97/59.94 material.
    """
    ticks = _timebase_ticks(timebase)
    if self._ticks < 0:
        raise ValueError("cannot format a negative time as timecode")
    number = self._ticks // ticks
    nominal = _nominal_fps(ticks)
    if drop_frame:
        dropped = _drop_count(ticks)
        per_ten_minutes = nominal * 600 - dropped * 9
        per_minute = nominal * 60 - dropped
        tens, rest = divmod(number, per_ten_minutes)
        if rest > dropped:
            number += dropped * 9 * tens + dropped * (
                (rest - dropped) // per_minute
            )
        else:
            number += dropped * 9 * tens
    seconds_total, frames = divmod(number, nominal)
    minutes_total, seconds = divmod(seconds_total, 60)
    hours, minutes = divmod(minutes_total, 60)
    separator = ";" if drop_frame else ":"
    return f"{hours:02d}:{minutes:02d}:{seconds:02d}{separator}{frames:02d}"