{"record":{"id":"f3929f377394abf9","repo":"ccfddl/ccf-deadlines","slug":"tz-str","errorCode":null,"errorMessage":"无效的时区格式: {tz_str}","messagePattern":"无效的时区格式: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"extensions/cli/ccfddl/convert_to_ical.py","lineNumber":30,"sourceCode":"    with open(path, encoding=\"utf-8\") as f:\n        types = yaml.safe_load(f)\n    if types is None:\n        return {}\n    SUB_MAPPING = {}\n    for types_data in types:\n        SUB_MAPPING[types_data[\"sub\"]] = types_data[\"name\"]\n    return SUB_MAPPING\n\n\ndef get_timezone(tz_str: str) -> timezone:\n    \"\"\"将时区字符串转换为datetime.timezone对象\"\"\"\n    if tz_str == \"AoE\":\n        return timezone(timedelta(hours=-12))\n    if tz_str == \"UTC\":\n        return timezone.utc\n    match = re.match(r\"UTC([+-])(\\d{1,2})$\", tz_str)\n    if not match:\n        raise ValueError(f\"无效的时区格式: {tz_str}\")\n    sign, hours = match.groups()\n    offset = int(hours) if sign == \"+\" else -int(hours)\n    return timezone(timedelta(hours=offset))\n\n\ndef create_vtimezone(tz: timezone) -> Timezone:\n    \"\"\"创建VTIMEZONE组件\"\"\"\n    tz_offset = tz.utcoffset(datetime.now())\n    offset_hours = tz_offset.total_seconds() // 3600\n    tzid = f\"UTC{offset_hours:+03.0f}:00\"\n\n    vtz = Timezone()\n    vtz.add(\"TZID\", tzid)\n\n    std = TimezoneStandard()\n    std.add(\"DTSTART\", datetime(1970, 1, 1))\n    std.add(\"TZOFFSETFROM\", timedelta(hours=offset_hours))\n    std.add(\"TZOFFSETTO\", timedelta(hours=offset_hours))","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/ccfddl/ccf-deadlines/blob/dedf5e76ab05c38b3cba2ba4f1fbf4d04fd403ba/extensions/cli/ccfddl/convert_to_ical.py#L12-L48","documentation":"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}\").","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nget_timezone(\"Asia/Shanghai\")  # ValueError: 无效的时区格式: Asia/Shanghai\n// after\nget_timezone(\"UTC+8\")  # timezone(timedelta(hours=8))","handlingStrategy":"validation","validationCode":"import re\ndef is_supported_tz(tz_str):\n    return tz_str in (\"AoE\", \"UTC\") or re.match(r\"UTC([+-])(\\d{1,2})$\", tz_str) is not None\n\nassert is_supported_tz(tz_str), f\"unsupported timezone: {tz_str}\"","typeGuard":null,"tryCatchPattern":"try:\n    tz = get_timezone(tz_str)\nexcept ValueError as e:\n    logging.error(\"skipping entry with bad timezone: %s\", e)\n    tz = timezone.utc  # or skip the entry","preventionTips":["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'."],"tags":["timezone","python","validation","cli","regex"],"backgroundTag":"invalid-argument-format","analyzedSha":"dedf5e76ab05c38b3cba2ba4f1fbf4d04fd403ba","analyzedAt":"2026-09-11T16:18:10.249Z","contentChangedAt":"2026-09-11T16:18:10.249Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}