DfttTimeRange API#

class DfttTimeRange[source]#

Bases: object

High-precision timerange class for representing time intervals.

DfttTimeRange represents a time interval with a start point, duration, and direction. It provides comprehensive operations for manipulating time ranges including offset, extend, shorten, reverse, retime, intersection, and union operations.

The class uses fractions.Fraction internally for precise calculations, ensuring frame-accurate operations even with complex interval manipulations.

Parameters:
  • start_tc – Start timecode. Can be a DfttTimecode object or any value that can construct a DfttTimecode. Required if not using precise parameters.

  • end_tc – End timecode. Can be a DfttTimecode object or any value that can construct a DfttTimecode. Required if not using precise parameters.

  • forward – Direction of the timerange. True for forward (start < end), False for backward (start > end). Defaults to True.

  • fps – Frame rate in frames per second. Used when constructing timecodes from non-timecode values. Defaults to 24.0.

  • start_precise_time – Internal construction parameter - precise start time as Fraction. Use with precise_duration for direct construction.

  • precise_duration – Internal construction parameter - precise duration as Fraction. Use with start_precise_time for direct construction.

  • strict_24h – Enable 24-hour constraint mode. When True, the timerange duration cannot exceed 24 hours and midnight-crossing ranges are handled specially. Defaults to False.

fps#

Frame rate of the timerange

Type:

float

forward#

Direction of the timerange

Type:

bool

strict_24h#

Whether 24-hour constraint is enabled

Type:

bool

precise_duration#

Duration as high-precision Fraction

Type:

Fraction

start_precise_time#

Start time as high-precision Fraction

Type:

Fraction

end_precise_time#

End time as high-precision Fraction

Type:

Fraction

duration#

Duration in seconds (absolute value)

Type:

float

framecount#

Duration in frames (absolute value)

Type:

int

start#

Start timecode object

Type:

DfttTimecode

end#

End timecode object

Type:

DfttTimecode

Raises:

Examples

Create from two timecodes:

>>> tr = DfttTimeRange('01:00:00:00', '02:00:00:00', fps=24)
>>> print(tr.duration)
3600.0
>>> print(tr.framecount)
86400

Create backward timerange:

>>> tr = DfttTimeRange('02:00:00:00', '01:00:00:00', forward=False, fps=24)
>>> print(tr.start)
02:00:00:00
>>> print(tr.end)
01:00:00:00

Operations:

>>> tr = DfttTimeRange('01:00:00:00', '01:10:00:00', fps=24)
>>> tr2 = tr.offset(600)  # Move forward 600 seconds (10 minutes)
>>> print(tr2.start)
01:10:00:00
>>> tr3 = tr.extend(300)  # Add 5 minutes to duration
>>> print(tr3.duration)
900.0

Iteration:

>>> tr = DfttTimeRange('01:00:00:00', '01:00:00:10', fps=24)
>>> for tc in tr:
...     print(tc)
01:00:00:00
01:00:00:01
...
01:00:00:09

Set operations:

>>> tr1 = DfttTimeRange('01:00:00:00', '02:00:00:00', fps=24)
>>> tr2 = DfttTimeRange('01:30:00:00', '02:30:00:00', fps=24)
>>> intersection = tr1 & tr2  # Intersection operator
>>> print(intersection.start)
01:30:00:00
>>> union = tr1 | tr2  # Union operator
>>> print(union.duration)
5400.0

Note

  • Timerange objects are immutable. All operations return new instances.

  • The internal representation uses fractions.Fraction for precision.

  • Forward and backward timeranges behave differently in some operations.

  • Zero-length timeranges are not allowed.

See also

  • DfttTimecode: For working with individual timecodes

  • dftt_timecode.error: Custom exception classes

TIME_24H_SECONDS = 86400#

Constant representing 24 hours in seconds (86400).

__init__(start_tc=None, end_tc=None, forward=True, fps=24.0, start_precise_time=None, precise_duration=None, strict_24h=False)[source]#
Parameters:
property fps: float#

Frame rate of the timerange

property forward: bool#

Direction of the timerange

property strict_24h: bool#

Whether timerange is constrained to 24 hours

property precise_duration: Fraction#

Precise duration as Fraction to avoid calculation errors

property start_precise_time: Fraction#

Start time as precise Fraction

property end_precise_time: Fraction#

End time as precise Fraction

property duration: float#

Duration in seconds

property framecount: int#

Duration in frames

property start: DfttTimecode#

Start timecode

property end: DfttTimecode#

End timecode

offset(offset_value)[source]#

Move timerange in time while preserving duration.

Shifts the entire timerange by the specified offset amount without changing the duration. Both start and end points move by the same amount.

Parameters:

offset_value (float | DfttTimecode | str | int) – Amount to offset the timerange. Can be: - float: Seconds to shift - int: Frames to shift (converted using current fps) - DfttTimecode: Uses the timecode’s timestamp - str: Timecode string to parse

Returns:

New timerange with shifted start/end points

Return type:

DfttTimeRange

Raises:

DFTTTimeRangeMethodError – If offset_value cannot be parsed

Examples

>>> tr = DfttTimeRange('01:00:00:00', '01:10:00:00', fps=24)
>>> tr2 = tr.offset(600)  # Offset by 10 minutes (600 seconds)
>>> print(tr2.start)
01:10:00:00
>>> print(tr2.end)
01:20:00:00

Note

In strict_24h mode, the new start time wraps around at 24 hours.

extend(extend_value)[source]#

Extend duration (positive value increases duration).

Extends or shortens the timerange by modifying the end point while keeping the start point fixed. Positive values increase duration, negative values decrease it.

Parameters:

extend_value (int | float | DfttTimecode | str) – Amount to extend the duration. Can be: - int or float: Seconds to extend (positive) or shorten (negative) - DfttTimecode: Uses the timecode’s timestamp - str: Timecode string to parse

Returns:

New timerange with modified duration

Return type:

DfttTimeRange

Raises:

Examples

>>> tr = DfttTimeRange('01:00:00:00', '01:10:00:00', fps=24)
>>> tr2 = tr.extend(300)  # Add 5 minutes
>>> print(tr2.duration)
900.0
>>> tr3 = tr.extend(-300)  # Subtract 5 minutes
>>> print(tr3.duration)
300.0

Note

The direction (forward/backward) affects how extension is applied.

shorten(shorten_value)[source]#

Shorten duration (positive value decreases duration).

This is a convenience method that calls extend() with a negated value. Shortens the timerange by modifying the end point while keeping the start fixed.

Parameters:

shorten_value (int | float | DfttTimecode | str) – Amount to shorten the duration. Can be: - int or float: Seconds to shorten (positive decreases duration) - DfttTimecode: Uses the timecode’s timestamp - str: Timecode string to parse

Returns:

New timerange with shortened duration

Return type:

DfttTimeRange

Raises:

Examples

>>> tr = DfttTimeRange('01:00:00:00', '01:10:00:00', fps=24)
>>> tr2 = tr.shorten(300)  # Shorten by 5 minutes
>>> print(tr2.duration)
300.0
>>> print(tr2.end)
01:05:00:00

Note

Internally calls extend(-shorten_value) for numeric values.

reverse()[source]#

Reverse direction of timerange.

Creates a new timerange with swapped start/end points and inverted direction. The duration magnitude remains the same, but the direction is flipped.

Returns:

New timerange with reversed direction

Return type:

DfttTimeRange

Examples

>>> tr = DfttTimeRange('01:00:00:00', '02:00:00:00', fps=24, forward=True)
>>> print(tr.start, '->', tr.end)
01:00:00:00 -> 02:00:00:00
>>> tr_rev = tr.reverse()
>>> print(tr_rev.start, '->', tr_rev.end)
02:00:00:00 -> 01:00:00:00
>>> print(tr_rev.forward)
False
>>> print(tr.duration == tr_rev.duration)
True

Note

  • The new start becomes the old end

  • The forward flag is flipped

  • Duration magnitude is preserved

  • This is useful for working with timeranges that play backward

retime(retime_factor)[source]#

Change duration by multiplication factor.

Scales the timerange duration by the given factor while keeping the start point fixed. This is useful for time-stretching or speed-change operations.

Parameters:

retime_factor (int | float | Fraction) – Multiplication factor for the duration. Can be: - int or float: Factor to multiply duration by - Fraction: Precise rational factor Examples: 2.0 doubles duration, 0.5 halves it, 1.5 extends by 50%

Returns:

New timerange with scaled duration

Return type:

DfttTimeRange

Raises:

Examples

>>> tr = DfttTimeRange('01:00:00:00', '01:10:00:00', fps=24)
>>> print(tr.duration)
600.0
>>> tr2 = tr.retime(2.0)  # Double the duration
>>> print(tr2.duration)
1200.0
>>> print(tr2.end)
01:20:00:00
>>> tr3 = tr.retime(0.5)  # Half the duration (speed up)
>>> print(tr3.duration)
300.0
>>> # Can also use * operator
>>> tr4 = tr * 2
>>> print(tr4.duration)
1200.0

Note

  • Start point remains unchanged

  • Commonly used for speed ramping or time-stretching effects

  • Factor > 1 increases duration (slow down)

  • Factor < 1 decreases duration (speed up)

  • Can also use the * operator for the same effect

separate(num_parts)[source]#

Separate timerange into multiple equal parts.

Divides the timerange into a specified number of equal-duration sub-ranges. All parts have the same duration and are contiguous (adjacent with no gaps).

Parameters:

num_parts (int) – Number of parts to divide the timerange into (must be >= 2)

Returns:

List of timerange parts, ordered from start to end

Return type:

List[DfttTimeRange]

Raises:

DFTTTimeRangeValueError – If num_parts is less than 2

Examples

>>> tr = DfttTimeRange('01:00:00:00', '01:01:00:00', fps=24)
>>> parts = tr.separate(4)  # Split into 4 equal parts
>>> len(parts)
4
>>> for i, part in enumerate(parts):
...     print(f"Part {i+1}: {part.start} - {part.end}, duration={part.duration}")
Part 1: 01:00:00:00 - 01:00:15:00, duration=15.0
Part 2: 01:00:15:00 - 01:00:30:00, duration=15.0
Part 3: 01:00:30:00 - 01:00:45:00, duration=15.0
Part 4: 01:00:45:00 - 01:01:00:00, duration=15.0
>>> # Each part has equal duration
>>> all(part.duration == tr.duration / 4 for part in parts)
True

Note

  • Each part has duration = original_duration / num_parts

  • Parts are contiguous (no gaps or overlaps)

  • All parts inherit the same fps, forward direction, and strict_24h mode

  • For backward timeranges, parts are still ordered from start to end

  • Useful for splitting work into parallel chunks or creating segments

contains(item, strict_forward=False)[source]#

Check if timerange contains another timerange or timecode.

Parameters:
  • item (DfttTimecode | DfttTimeRange | str | int | float) – Item to check for containment. Can be: - DfttTimecode: Checks if timecode is within range - DfttTimeRange: Checks if entire timerange is contained - str, int, float: Converted to timecode for checking

  • strict_forward (bool) – If True, requires contained timerange to have same direction. Only applies when item is a DfttTimeRange. Defaults to False.

Returns:

True if item is contained within this timerange, False otherwise

Return type:

bool

Raises:

DFTTTimeRangeTypeError – If item cannot be converted to timecode

Examples

>>> tr = DfttTimeRange('01:00:00:00', '02:00:00:00', fps=24)
>>> tc = DfttTimecode('01:30:00:00', fps=24)
>>> tr.contains(tc)
True
>>> tr.contains('00:30:00:00')
False
>>> tr2 = DfttTimeRange('01:10:00:00', '01:50:00:00', fps=24)
>>> tr.contains(tr2)
True

Note

For backward timeranges, containment is checked accordingly.

intersect(other)[source]#

Calculate intersection of two timeranges (AND operation).

Returns the overlapping portion of two timeranges. Both timeranges must have the same direction and frame rate.

Parameters:

other (DfttTimeRange) – Another DfttTimeRange to intersect with

Returns:

New timerange representing the intersection, or None if no overlap

Return type:

DfttTimeRange

Raises:

Examples

>>> tr1 = DfttTimeRange('01:00:00:00', '02:00:00:00', fps=24)
>>> tr2 = DfttTimeRange('01:30:00:00', '02:30:00:00', fps=24)
>>> intersection = tr1.intersect(tr2)
>>> print(intersection.start)
01:30:00:00
>>> print(intersection.end)
02:00:00:00
>>> # Can also use & operator
>>> intersection = tr1 & tr2

Note

  • Returns None if timeranges don’t overlap

  • Strict_24h is True only if both input timeranges have it enabled

union(other)[source]#

Calculate union of two timeranges (OR operation).

Combines two overlapping or adjacent timeranges into a single continuous timerange that spans from the earliest start to the latest end. Both timeranges must have the same direction and frame rate, and must either overlap or be adjacent (touching) with no gap between them.

Parameters:

other (DfttTimeRange) – Another DfttTimeRange to union with

Returns:

New timerange spanning both input ranges

Return type:

DfttTimeRange

Raises:

Examples

Overlapping timeranges:

>>> tr1 = DfttTimeRange('01:00:00:00', '01:30:00:00', fps=24)
>>> tr2 = DfttTimeRange('01:20:00:00', '02:00:00:00', fps=24)
>>> union = tr1.union(tr2)
>>> print(union.start)
01:00:00:00
>>> print(union.end)
02:00:00:00
>>> print(union.duration)
3600.0

Adjacent (touching) timeranges:

>>> tr1 = DfttTimeRange('01:00:00:00', '01:30:00:00', fps=24)
>>> tr2 = DfttTimeRange('01:30:00:00', '02:00:00:00', fps=24)
>>> union = tr1.union(tr2)  # No gap, they touch
>>> print(union.start)
01:00:00:00
>>> print(union.end)
02:00:00:00

Using the | operator:

>>> tr1 = DfttTimeRange('01:00:00:00', '01:30:00:00', fps=24)
>>> tr2 = DfttTimeRange('01:20:00:00', '02:00:00:00', fps=24)
>>> union = tr1 | tr2  # Shorthand for union
>>> print(union.duration)
3600.0

Non-adjacent timeranges (will fail):

>>> tr1 = DfttTimeRange('01:00:00:00', '01:30:00:00', fps=24)
>>> tr2 = DfttTimeRange('02:00:00:00', '02:30:00:00', fps=24)
>>> union = tr1.union(tr2)  # Gap of 30 minutes
DFTTTimeRangeMethodError: Cannot union non-overlapping, non-adjacent timeranges

Note

  • Timeranges must overlap or be adjacent (no gap allowed)

  • The result spans from earliest start to latest end

  • Direction must be the same for both timeranges

  • Strict_24h is True only if both input timeranges have it enabled

  • This is a set operation, different from add() which combines durations

  • Can also use the | operator as a shorthand

  • For checking overlap, use intersect() first

See also

  • intersect(): Get the overlapping portion (AND operation)

  • add(): Add durations (different from union)

add(other)[source]#

Add durations of two timeranges (direction-sensitive).

Combines the durations of two timeranges to create a new timerange with extended duration. The behavior depends on whether the timeranges have the same or opposite directions.

Parameters:

other (DfttTimeRange) – Another DfttTimeRange to add

Returns:

New timerange with combined duration, same start point

and direction as the original

Return type:

DfttTimeRange

Raises:

Examples

>>> tr1 = DfttTimeRange('01:00:00:00', '01:10:00:00', fps=24)  # 10 min
>>> tr2 = DfttTimeRange('01:00:00:00', '01:05:00:00', fps=24)  # 5 min
>>> tr3 = tr1.add(tr2)
>>> print(tr3.duration)  # Same direction: 10 + 5 = 15 min
900.0
>>> tr4 = DfttTimeRange('01:10:00:00', '01:00:00:00', forward=False, fps=24)
>>> tr5 = tr1.add(tr4)
>>> print(tr5.duration)  # Opposite direction: 10 - 10 = 0 (error)
DFTTTimeRangeValueError

Note

  • Same direction: durations are added (extend)

  • Opposite direction: durations are subtracted (shorten)

  • Start point remains unchanged

  • This is different from union() which combines overlapping ranges

subtract(other)[source]#

Subtract durations of two timeranges (direction-sensitive).

Subtracts the duration of another timerange from this one to create a new timerange with reduced duration. The behavior depends on whether the timeranges have the same or opposite directions.

Parameters:

other (DfttTimeRange) – Another DfttTimeRange to subtract

Returns:

New timerange with reduced duration, same start point

and direction as the original

Return type:

DfttTimeRange

Raises:

Examples

>>> tr1 = DfttTimeRange('01:00:00:00', '01:10:00:00', fps=24)  # 10 min
>>> tr2 = DfttTimeRange('01:00:00:00', '01:03:00:00', fps=24)  # 3 min
>>> tr3 = tr1.subtract(tr2)
>>> print(tr3.duration)  # Same direction: 10 - 3 = 7 min
420.0
>>> print(tr3.end)
01:07:00:00
>>> # With opposite directions
>>> tr4 = DfttTimeRange('01:10:00:00', '01:08:00:00', forward=False, fps=24)
>>> tr5 = tr1.subtract(tr4)  # 10 - (-2) = 12 min
>>> print(tr5.duration)
720.0

Note

  • Same direction: durations are subtracted (shorten)

  • Opposite direction: durations are added (extend)

  • Start point remains unchanged

  • This is the inverse operation of add()

  • Can result in zero-length error if durations are equal

__str__()[source]#

Return str(self).

Return type:

str

__repr__()[source]#

Return repr(self).

Return type:

str

__contains__(item)[source]#
Return type:

bool

__iter__()[source]#

Iterate through timecodes in the range

Return type:

Iterator[DfttTimecode]

__add__(other)[source]#

Add operator for timeranges

Return type:

DfttTimeRange

__sub__(other)[source]#

Subtract operator for timeranges

Return type:

DfttTimeRange

__mul__(factor)[source]#

Multiply duration by factor

Return type:

DfttTimeRange

__truediv__(factor)[source]#

Divide duration by factor

Return type:

DfttTimeRange

__and__(other)[source]#

Intersection operator

Return type:

DfttTimeRange | None

__or__(other)[source]#

Union operator

Return type:

DfttTimeRange

__eq__(other)[source]#

Equality comparison

Return type:

bool

__ne__(other)[source]#

Inequality comparison

Return type:

bool

__lt__(other)[source]#

Less than comparison based on start time

Return type:

bool

__le__(other)[source]#

Less than or equal comparison

Return type:

bool

__gt__(other)[source]#

Greater than comparison

Return type:

bool

__ge__(other)[source]#

Greater than or equal comparison

Return type:

bool

Core Class#

The DfttTimeRange class represents a time range with start and end points, built on top of DfttTimecode.

Examples#

Basic Usage#

from dftt_timecode import DfttTimecode, DfttTimeRange

# Create time range
start = DfttTimecode('01:00:00:00', 'auto', fps=24)
end = DfttTimecode('02:00:00:00', 'auto', fps=24)
range1 = DfttTimeRange(start, end)

# Get duration
print(range1.duration.timecode_output('smpte'))  # '01:00:00:00'

Checking Containment and Intersection#

tc = DfttTimecode('01:30:00:00', 'auto', fps=24)

# Check if timecode is within range
if tc in range1:
    print("Timecode is within range")

# Create another range
range2 = DfttTimeRange(
    DfttTimecode('01:30:00:00', 'auto', fps=24),
    DfttTimecode('02:30:00:00', 'auto', fps=24)
)

# Get intersection of two ranges
intersection = range1.intersect(range2)
print(intersection)