{"record":{"id":"8564f04a4c7735e4","repo":"VictoriaMetrics/VictoriaMetrics","slug":"cannot-parse-minute-from-timezone-offset-q-w","errorCode":null,"errorMessage":"cannot parse minute from timezone offset %q: %w","messagePattern":"cannot parse minute from timezone offset %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/timeutil/time.go","lineNumber":50,"sourceCode":"// It returns unix timestamp in nanoseconds.\nfunc ParseTimeAt(s string, currentTimestamp int64) (int64, error) {\n\tif s == \"now\" {\n\t\treturn currentTimestamp, nil\n\t}\n\tsOrig := s\n\ttzOffset := int64(0)\n\tif len(sOrig) > 6 {\n\t\t// Try parsing timezone offset\n\t\ttz := sOrig[len(sOrig)-6:]\n\t\tif (tz[0] == '-' || tz[0] == '+') && tz[3] == ':' {\n\t\t\tisPlus := tz[0] == '+'\n\t\t\thour, err := strconv.ParseUint(tz[1:3], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, fmt.Errorf(\"cannot parse hour from timezone offset %q: %w\", tz, err)\n\t\t\t}\n\t\t\tminute, err := strconv.ParseUint(tz[4:], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, fmt.Errorf(\"cannot parse minute from timezone offset %q: %w\", tz, err)\n\t\t\t}\n\t\t\ttzOffset = int64(hour*3600+minute*60) * 1e9\n\t\t\tif isPlus {\n\t\t\t\ttzOffset = -tzOffset\n\t\t\t}\n\t\t\ts = sOrig[:len(sOrig)-6]\n\t\t} else {\n\t\t\tif !strings.HasSuffix(s, \"Z\") {\n\t\t\t\ttzOffset = -GetLocalTimezoneOffsetNsecs()\n\t\t\t} else {\n\t\t\t\ts = s[:len(s)-1]\n\t\t\t}\n\t\t}\n\t}\n\ts = strings.TrimSuffix(s, \"Z\")\n\tif len(s) > 0 && (s[len(s)-1] > '9' || s[0] == '-') || strings.HasPrefix(s, \"now\") {\n\t\t// Parse duration relative to the current time\n\t\ts = strings.TrimPrefix(s, \"now\")","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/VictoriaMetrics/VictoriaMetrics/blob/5079fb58f1e8e62113f90c945ad71586c797d770/lib/timeutil/time.go#L32-L68","documentation":"Fires in ParseTimeAt when the trailing timezone offset of a timestamp string (the last 6 characters, e.g. +05:30) has a sign and colon but its minute part (characters after the colon) is not a valid unsigned integer. ParseTimeAt cannot apply the offset, so the whole timestamp fails to parse.","triggerScenarios":"ParseTimeAt / ParseTimeMsec with timestamps like `\"2024-01-02T10:00:00+02:MM\"` or `\"...+02:--\"` — the last 6 chars look like an offset but tz[4:] is not a valid digit string.","commonSituations":"Corrupted log timestamps; placeholders like `+HH:MM` never substituted with real digits; truncation/encoding issues mangling the tail of an RFC3339 string.","solutions":["Supply a complete RFC3339 offset, e.g. `2024-01-02T10:00:00+02:30`","Fix the upstream producer that emits placeholder minutes","Parse the timestamp yourself (time.Parse with the right layout) if inputs are nonstandard"],"exampleFix":"// before\nParseTimeAt(\"2024-01-02T10:00:00+02:MM\", nil)\n// after\nParseTimeAt(\"2024-01-02T10:00:00+02:30\", nil)","handlingStrategy":"validation","validationCode":"var tzRe = regexp.MustCompile(`[+-]([0-9]{2}):([0-9]{2})$`)\nfunc validOffsetMinutes(s string) bool {\n\tm := tzRe.FindStringSubmatch(s)\n\tif m == nil {\n\t\treturn false\n\t}\n\t_, err1 := strconv.ParseUint(m[1], 10, 64)\n\t_, err2 := strconv.ParseUint(m[2], 10, 64)\n\treturn err1 == nil && err2 == nil\n}","typeGuard":"func hasRFC3339Offset(s string) bool {\n\t_, err := time.Parse(time.RFC3339, s)\n\treturn err == nil\n}","tryCatchPattern":"ts, err := timeutil.ParseTimeMsec(s, nil)\nif err != nil {\n\tlog.Printf(\"skipping malformed timestamp %q: %v\", s, err)\n}","preventionTips":["Validate RFC3339 format upstream before calling ParseTimeAt/ParseTimeMsec","Expand `+HH:MM` placeholders in templates and fail fast if unsubstituted"],"tags":["time","parsing","timezone"],"backgroundTag":"invalid-timestamp-format","analyzedSha":"5079fb58f1e8e62113f90c945ad71586c797d770","analyzedAt":"2026-09-03T18:10:26.153Z","contentChangedAt":"2026-09-03T18:10:26.153Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}