ccfddl/ccf-deadlines · error · ValueError
无效的时区格式
Error message
无效的时区格式: {tz_str} What it means
get_timezone in extensions/cli/ccfddl/convert_to_ical.py converts a timezone string into a Python datetime.timezone. It only accepts the literals 'AoE' (UTC-12) and 'UTC', plus strings matching UTC[+-]<1-2 digits> (e.g. UTC+8, UTC-05). Any other string fails the regex and raises ValueError("无效的时区格式: {tz_str}").
Solutions
- Rewrite the timezone string to the accepted format, e.g. 'Asia/Shanghai' → 'UTC+8', keeping the exact capitalization 'UTC' and no minutes.
- Use the literal 'AoE' for anywhere-on-earth deadlines or 'UTC' for zero offset instead of 'UTC+0'/'GMT'.
- Preprocess input data to normalize abbreviations/IANA names to UTC±h before calling the converter.
- Extend get_timezone's regex to also accept minute offsets (UTC±HH:MM) or use zoneinfo.ZoneInfo for IANA names.
Example fix
// before
get_timezone("Asia/Shanghai") # ValueError: 无效的时区格式: Asia/Shanghai
// after
get_timezone("UTC+8") # timezone(timedelta(hours=8)) Defensive patterns
Strategy: validation
Validate before calling
import re
def is_supported_tz(tz_str):
return tz_str in ("AoE", "UTC") or re.match(r"UTC([+-])(\d{1,2})$", tz_str) is not None
assert is_supported_tz(tz_str), f"unsupported timezone: {tz_str}" Try / catch
try:
tz = get_timezone(tz_str)
except ValueError as e:
logging.error("skipping entry with bad timezone: %s", e)
tz = timezone.utc # or skip the entry Prevention
- Normalize timezone strings (strip whitespace, canonical case) before conversion.
- Map common abbreviations and IANA names to UTC±h offsets in a preprocessing step.
- Keep a unit test enumerating every tz string your data sources can emit.
- Prefer 'AoE'/'UTC' literals for the special cases instead of 'UTC+0' or 'GMT'.
When it happens
Trigger: Calling convert_to_ical (or get_timezone directly) with a deadline timezone string that is not 'AoE', 'UTC', or 'UTC±H' — e.g. 'Asia/Shanghai', 'GMT+8', 'UTC+8:30', 'utc+8' (case-sensitive), 'PST', or an empty string.
Common situations: Feeding the converter ICS/config data whose TZID or timezone field uses IANA zone names or abbreviations instead of the UTC±h offset convention this CLI expects; hand-editing a config and writing lowercase 'utc+8'; timezones with minute offsets like UTC+5:30 which the \d{1,2} regex rejects.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of ccfddl/ccf-deadlines@dedf5e76ab (2026-09-11).
Data as JSON: /api/errors/f3929f377394abf9.
Report an issue: GitHub.
Appendix: source
Thrown at extensions/cli/ccfddl/convert_to_ical.py:30
with open(path, encoding="utf-8") as f:
types = yaml.safe_load(f)
if types is None:
return {}
SUB_MAPPING = {}
for types_data in types:
SUB_MAPPING[types_data["sub"]] = types_data["name"]
return SUB_MAPPING
def get_timezone(tz_str: str) -> timezone:
"""将时区字符串转换为datetime.timezone对象"""
if tz_str == "AoE":
return timezone(timedelta(hours=-12))
if tz_str == "UTC":
return timezone.utc
match = re.match(r"UTC([+-])(\d{1,2})$", tz_str)
if not match:
raise ValueError(f"无效的时区格式: {tz_str}")
sign, hours = match.groups()
offset = int(hours) if sign == "+" else -int(hours)
return timezone(timedelta(hours=offset))
def create_vtimezone(tz: timezone) -> Timezone:
"""创建VTIMEZONE组件"""
tz_offset = tz.utcoffset(datetime.now())
offset_hours = tz_offset.total_seconds() // 3600
tzid = f"UTC{offset_hours:+03.0f}:00"
vtz = Timezone()
vtz.add("TZID", tzid)
std = TimezoneStandard()
std.add("DTSTART", datetime(1970, 1, 1))
std.add("TZOFFSETFROM", timedelta(hours=offset_hours))
std.add("TZOFFSETTO", timedelta(hours=offset_hours))View on GitHub (pinned to dedf5e76ab)