(time_str)
| 4030 | # Helper parse functions |
| 4031 | # ------------------------------- |
| 4032 | def parse_xmltv_time(time_str): |
| 4033 | try: |
| 4034 | # Basic format validation |
| 4035 | if len(time_str) < 14: |
| 4036 | logger.warning(f"XMLTV timestamp too short: '{time_str}', using as-is") |
| 4037 | dt_obj = datetime.strptime(time_str, '%Y%m%d%H%M%S') |
| 4038 | return timezone.make_aware(dt_obj, timezone=dt_timezone.utc) |
| 4039 | |
| 4040 | # Parse base datetime |
| 4041 | dt_obj = datetime.strptime(time_str[:14], '%Y%m%d%H%M%S') |
| 4042 | |
| 4043 | # Handle timezone if present |
| 4044 | if len(time_str) >= 20: # Has timezone info |
| 4045 | tz_sign = time_str[15] |
| 4046 | tz_hours = int(time_str[16:18]) |
| 4047 | tz_minutes = int(time_str[18:20]) |
| 4048 | |
| 4049 | # Create a timezone object |
| 4050 | if tz_sign == '+': |
| 4051 | tz_offset = dt_timezone(timedelta(hours=tz_hours, minutes=tz_minutes)) |
| 4052 | elif tz_sign == '-': |
| 4053 | tz_offset = dt_timezone(timedelta(hours=-tz_hours, minutes=-tz_minutes)) |
| 4054 | else: |
| 4055 | tz_offset = dt_timezone.utc |
| 4056 | |
| 4057 | # Make datetime aware with correct timezone |
| 4058 | aware_dt = datetime.replace(dt_obj, tzinfo=tz_offset) |
| 4059 | # Convert to UTC |
| 4060 | aware_dt = aware_dt.astimezone(dt_timezone.utc) |
| 4061 | |
| 4062 | logger.trace(f"Parsed XMLTV time '{time_str}' to {aware_dt}") |
| 4063 | return aware_dt |
| 4064 | else: |
| 4065 | # No timezone info, assume UTC |
| 4066 | aware_dt = timezone.make_aware(dt_obj, timezone=dt_timezone.utc) |
| 4067 | logger.trace(f"Parsed XMLTV time without timezone '{time_str}' as UTC: {aware_dt}") |
| 4068 | return aware_dt |
| 4069 | |
| 4070 | except Exception as e: |
| 4071 | logger.error(f"Error parsing XMLTV time '{time_str}': {e}", exc_info=True) |
| 4072 | raise |
| 4073 | |
| 4074 | |
| 4075 | def parse_schedules_direct_time(time_str): |
no outgoing calls
no test coverage detected