CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pysrt

SubRip (.srt) subtitle parser and writer for Python

Pending
Overview
Eval results
Files

time-handling.mddocs/

Time Handling

Time representation and manipulation through the SubRipTime class. Supports the standard SubRip time format (HH:MM:SS,mmm), arithmetic operations, format conversion, and coercion from various input types.

Capabilities

Time Creation

Create time objects from various sources and formats.

class SubRipTime:
    def __init__(self, hours=0, minutes=0, seconds=0, milliseconds=0):
        """
        Create a new SubRipTime instance.
        
        Args:
            hours (int): Hour component (default: 0)
            minutes (int): Minute component (default: 0)
            seconds (int): Second component (default: 0)
            milliseconds (int): Millisecond component (default: 0)
        """

    @classmethod
    def coerce(cls, other):
        """
        Convert various types to SubRipTime instance.
        
        Args:
            other: Input to convert (str, int, datetime.time, dict, tuple, or SubRipTime)
            
        Returns:
            SubRipTime: Converted time object
            
        Supported types:
            - str/unicode: "HH:MM:SS,mmm" format
            - int: Total milliseconds
            - datetime.time: Standard time object
            - dict: {'hours': h, 'minutes': m, 'seconds': s, 'milliseconds': ms}
            - tuple/list: (hours, minutes, seconds, milliseconds)
        """

    @classmethod
    def from_string(cls, source):
        """
        Parse time from SubRip format string.
        
        Args:
            source (str): Time string in "HH:MM:SS,mmm" format
            
        Returns:
            SubRipTime: Parsed time object
            
        Raises:
            InvalidTimeString: If format is invalid
        """

    @classmethod
    def from_ordinal(cls, ordinal):
        """
        Create time from total millisecond count.
        
        Args:
            ordinal (int): Total milliseconds
            
        Returns:
            SubRipTime: Time object representing the duration
        """

    @classmethod
    def from_time(cls, source):
        """
        Create time from datetime.time object.
        
        Args:
            source (datetime.time): Standard time object
            
        Returns:
            SubRipTime: Converted time object
        """
        
    @classmethod
    def parse_int(cls, digits):
        """
        Parse integer from string with error tolerance.
        
        Args:
            digits (str): String containing digits
            
        Returns:
            int: Parsed integer value (0 if parsing fails)
        """

Time Components

Access and modify individual time components.

@property
def hours(self):
    """
    Hour component (0-23).
    
    Returns:
        int: Hours
    """

@property
def minutes(self):
    """
    Minute component (0-59).
    
    Returns:
        int: Minutes
    """

@property
def seconds(self):
    """
    Second component (0-59).
    
    Returns:
        int: Seconds
    """

@property
def milliseconds(self):
    """
    Millisecond component (0-999).
    
    Returns:
        int: Milliseconds
    """

@property
def ordinal(self):
    """
    Total time in milliseconds.
    
    Returns:
        int: Total milliseconds since 00:00:00,000
    """

Time Operations

Perform arithmetic and timing operations.

def shift(self, *args, **kwargs):
    """
    Add time offset or apply ratio transformation.
    
    Args:
        *args: Positional time arguments (hours, minutes, seconds, milliseconds)
        **kwargs: Named time arguments or ratio for scaling
        
    Supported kwargs:
        hours (int): Hours to add
        minutes (int): Minutes to add
        seconds (int): Seconds to add
        milliseconds (int): Milliseconds to add
        ratio (float): Multiply time by this ratio
    """

def to_time(self):
    """
    Convert to standard datetime.time object.
    
    Returns:
        datetime.time: Standard Python time object
    """

Arithmetic Operations

SubRipTime supports arithmetic operations with other time objects.

# Addition
time1 + time2                    # Add two times
time += other_time               # In-place addition

# Subtraction  
time1 - time2                    # Subtract times
time -= other_time               # In-place subtraction

# Multiplication (scaling)
time * ratio                     # Scale time by ratio
time *= ratio                    # In-place scaling

Comparison Operations

Compare times using standard comparison operators.

time1 < time2                    # Earlier than
time1 <= time2                   # Earlier than or equal
time1 == time2                   # Equal times
time1 >= time2                   # Later than or equal
time1 > time2                    # Later than
time1 != time2                   # Not equal

String Representation

Convert times to various string formats.

def __str__(self):
    """
    Convert to SubRip format string.
    
    Returns:
        str: Time in "HH:MM:SS,mmm" format (negative times shown as 00:00:00,000)
    """

def __repr__(self):
    """
    Convert to Python representation.
    
    Returns:
        str: "SubRipTime(hours, minutes, seconds, milliseconds)" format
    """

Iteration Support

Iterate over time components.

def __iter__(self):
    """
    Iterate over time components.
    
    Yields:
        int: Hours, minutes, seconds, milliseconds in order
    """

Usage Examples

Creating Times

import pysrt
from datetime import time

# Create from components
t1 = pysrt.SubRipTime(1, 30, 45, 500)  # 01:30:45,500
print(t1)  # "01:30:45,500"

# Create from string
t2 = pysrt.SubRipTime.from_string("00:02:15,750")

# Create from total milliseconds
t3 = pysrt.SubRipTime.from_ordinal(135500)  # 00:02:15,500

# Create from datetime.time
py_time = time(14, 30, 15, 250000)  # 250000 microseconds = 250 ms
t4 = pysrt.SubRipTime.from_time(py_time)

# Coerce from various formats
t5 = pysrt.SubRipTime.coerce("01:23:45,678")
t6 = pysrt.SubRipTime.coerce(90000)  # 90 seconds in milliseconds
t7 = pysrt.SubRipTime.coerce({'minutes': 5, 'seconds': 30})
t8 = pysrt.SubRipTime.coerce((0, 1, 30, 0))  # tuple format

Time Arithmetic

# Basic arithmetic  
start = pysrt.SubRipTime(0, 1, 0, 0)    # 00:01:00,000
duration = pysrt.SubRipTime(0, 0, 3, 500) # 00:00:03,500
end = start + duration                   # 00:01:03,500

# Time differences
total_time = pysrt.SubRipTime(1, 30, 0, 0)
elapsed = pysrt.SubRipTime(0, 45, 30, 0)
remaining = total_time - elapsed         # 00:44:30,000

# Scaling operations
original = pysrt.SubRipTime(0, 2, 0, 0)  # 2 minutes
double_speed = original * 0.5            # 1 minute (half duration)
slow_motion = original * 2.0             # 4 minutes (double duration)

Component Access

time_obj = pysrt.SubRipTime(2, 15, 30, 750)  # 02:15:30,750

# Access components
print(f"Hours: {time_obj.hours}")           # 2
print(f"Minutes: {time_obj.minutes}")       # 15
print(f"Seconds: {time_obj.seconds}")       # 30
print(f"Milliseconds: {time_obj.milliseconds}") # 750

# Total milliseconds
print(f"Total ms: {time_obj.ordinal}")      # 8130750

# Component modification
time_obj.hours = 3
time_obj.minutes = 0
print(time_obj)  # "03:00:30,750"

# Iteration over components
hours, minutes, seconds, ms = time_obj
components = list(time_obj)  # [3, 0, 30, 750]

Time Shifting

# Offset operations
time_obj = pysrt.SubRipTime(1, 0, 0, 0)      # 01:00:00,000

# Add components
time_obj.shift(minutes=30, seconds=15)        # 01:30:15,000
time_obj.shift(hours=-1, milliseconds=500)   # 00:30:15,500

# Ratio scaling for framerate conversion
# Convert from 23.976 fps to 25 fps  
time_obj.shift(ratio=25/23.976)

# In-place operations
time_obj += pysrt.SubRipTime(0, 0, 5, 0)     # Add 5 seconds
time_obj -= pysrt.SubRipTime(0, 0, 2, 500)   # Subtract 2.5 seconds
time_obj *= 1.1                              # Scale by 10%

Format Conversion

# Convert to different formats
srt_time = pysrt.SubRipTime(14, 30, 15, 250)

# Standard Python time object
py_time = srt_time.to_time()
print(py_time)  # 14:30:15.250000

# String representations
print(str(srt_time))      # "14:30:15,250"
print(repr(srt_time))     # "SubRipTime(14, 30, 15, 250)"

# Total seconds (with decimal)
total_seconds = srt_time.ordinal / 1000.0  # 52215.25

# Format for different systems
ffmpeg_format = str(srt_time).replace(',', '.')  # "14:30:15.250"

Validation and Error Handling

try:
    # Invalid format
    bad_time = pysrt.SubRipTime.from_string("25:70:90,1500")
except pysrt.InvalidTimeString as e:
    print(f"Invalid time format: {e}")

# Negative time handling  
negative = pysrt.SubRipTime(0, 0, 5, 0) - pysrt.SubRipTime(0, 0, 10, 0)
print(negative.ordinal)  # -5000 (internal representation)
print(str(negative))     # "00:00:00,000" (displayed as zero)

# Very large times
large_time = pysrt.SubRipTime(99, 59, 59, 999)  # Maximum reasonable time
print(large_time)        # "99:59:59,999"

Advanced Usage

# Time-based subtitle operations
def adjust_subtitle_timing(subs, delay_ms):
    """Add delay to all subtitles"""
    delay = pysrt.SubRipTime.from_ordinal(delay_ms)
    for sub in subs:
        sub.start += delay
        sub.end += delay

def synchronize_subtitles(subs, reference_time, actual_time):
    """Sync subtitles based on a reference point"""
    ratio = actual_time.ordinal / reference_time.ordinal
    for sub in subs:
        sub.shift(ratio=ratio)

def find_gaps(subs, min_gap_ms=100):
    """Find gaps between subtitles"""
    gaps = []
    min_gap = pysrt.SubRipTime.from_ordinal(min_gap_ms)
    
    for i in range(len(subs) - 1):
        current_end = subs[i].end
        next_start = subs[i + 1].start
        gap = next_start - current_end
        
        if gap > min_gap:
            gaps.append((i, gap))
    
    return gaps

# Usage
subs = pysrt.open('movie.srt')
adjust_subtitle_timing(subs, 2500)  # 2.5 second delay
gaps = find_gaps(subs)
print(f"Found {len(gaps)} significant gaps")

Constants

TIME_PATTERN: str = '%02d:%02d:%02d,%03d'    # String format pattern
SECONDS_RATIO: int = 1000                    # Milliseconds per second
MINUTES_RATIO: int = 60000                   # Milliseconds per minute  
HOURS_RATIO: int = 3600000                   # Milliseconds per hour

Install with Tessl CLI

npx tessl i tessl/pypi-pysrt

docs

command-line.md

index.md

subtitle-files.md

subtitle-items.md

time-handling.md

tile.json