{"record":{"id":"1cf912e77be9601d","repo":"babalae/better-genshin-impact","slug":"timetext","errorCode":null,"errorMessage":"树脂恢复时间格式无效：{timeText}","messagePattern":"树脂恢复时间格式无效：(.+?)","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/AutoBoss/AutoBossTask.cs","lineNumber":429,"sourceCode":"            throw new FormatException($\"未识别到全部恢复时间：{text}\");\n        }\n\n        return ParseRecoveryTime(timeMatches[timeMatches.Count - 1].Value);\n    }\n\n    private static TimeSpan ParseRecoveryTime(string timeText)\n    {\n        var parts = timeText.Split(':');\n        if (parts.Length != 3\n            || !int.TryParse(parts[0], NumberStyles.None, CultureInfo.InvariantCulture, out var hours)\n            || !int.TryParse(parts[1], NumberStyles.None, CultureInfo.InvariantCulture, out var minutes)\n            || !int.TryParse(parts[2], NumberStyles.None, CultureInfo.InvariantCulture, out var seconds)\n            || minutes < 0\n            || minutes > 59\n            || seconds < 0\n            || seconds > 59)\n        {\n            throw new FormatException($\"树脂恢复时间格式无效：{timeText}\");\n        }\n\n        return new TimeSpan(hours, minutes, seconds);\n    }\n\n    private static string FormatRecoveryTime(TimeSpan time)\n    {\n        return $\"{(int)time.TotalHours:D2}:{time.Minutes:D2}:{time.Seconds:D2}\";\n    }\n\n    /// <summary>\n    /// 当前处于大地图树脂详情弹窗时，尝试使用须臾或脆弱树脂补充原粹树脂。\n    /// </summary>\n    private async Task<bool> TryUseSupplementalResinBeforeRound(OriginalResinInfo originalResin)\n    {\n        var page = new BvPage(_ct);\n        var currentResin = originalResin;\n        var unavailableResins = new HashSet<string>(StringComparer.Ordinal);","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/AutoBoss/AutoBossTask.cs#L411-L447","documentation":"ParseRecoveryTime 校验 H:MM:SS 三段：必须三段、均可解析、minutes/seconds 在 0..59。由于上游正则已要求 \\d{2}，hours 段 \\d{1,3} 总能解析；该异常实际触发于 minutes 或 seconds ≥ 60（例如 OCR 把 '05' 读成 '95'），即 OCR 数值越界。","triggerScenarios":"OCR 把时间某段读成 ≥60 的值（'12:95:00'）；冒号被识别为数字导致段数错位后又被正则误匹配；分割后某段含非数字（理论上正则已排除）。","commonSituations":"小字号 OCR 把 ':' 误读为数字或把相邻数字粘连；detailRect 区域噪声多；模型对游戏字体识别不稳。","solutions":["记录 timeText 原文确认哪段越界。","对越界值做钳制（clamp minutes/seconds 到 0..59）后重试，而非直接失败。","改进 OCR 前处理（二值化/放大）提升冒号识别率。","在外层兜底降级。"],"exampleFix":"// before\nif (minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59)\n{\n    throw new FormatException($\"树脂恢复时间格式无效：{timeText}\");\n}\n\n// after\nif (minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59)\n{\n    throw new FormatException($\"树脂恢复时间格式无效（分秒越界）：{timeText}\");\n}","handlingStrategy":"validation","validationCode":"// ParseRecoveryTime 内：越界值钳制而非抛出（仅当确信 OCR 单字符错误时）\n// 谨慎使用：钳制会改变结果。建议优先抛出并重试 OCR。","typeGuard":null,"tryCatchPattern":"try { return ParseRecoveryTime(value); }\ncatch (FormatException ex) { _logger.LogWarning(\"恢复时间解析失败 [{Value}]：{Msg}\", value, ex.Message); throw; }","preventionTips":["记录 timeText 原文定位越界段。","提升 OCR 前处理质量以减少数字粘连。","在重试层吸收偶发 OCR 错误。"],"tags":["ocr","resin","parse","time","genshin","autoboss"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}