kataras/iris · error
error parsing offset hours: %s: %w
Error message
error parsing offset hours: %s: %w
What it means
When parsing an unconventional '+HH:MM:SS' offset, adjustForUnconventionalOffset converts the hours field with strconv.Atoi. This error wraps the strconv failure, meaning the hours portion of the offset was not a plain integer. The offset text is included and the underlying strconv error is wrapped with %w.
Source
Thrown at x/jsonx/iso8601.go:237
parts := strings.Split(offset, ":")
return len(parts) == 3
}
func adjustForUnconventionalOffset(t time.Time, offset string) (time.Time, error) {
sign := 1
if offset[0] == '-' {
sign = -1
}
offset = offset[1:]
offsetParts := strings.Split(offset, ":")
if len(offsetParts) != 3 {
return time.Time{}, fmt.Errorf("invalid offset format: %s", offset)
}
hours, err := strconv.Atoi(offsetParts[0])
if err != nil {
return time.Time{}, fmt.Errorf("error parsing offset hours: %s: %w", offset, err)
}
if hours > 24 {
return time.Time{}, fmt.Errorf("invalid offset hours: %d: %s", hours, offset)
}
minutes, err := strconv.Atoi(offsetParts[1])
if err != nil {
return time.Time{}, fmt.Errorf("error parsing offset minutes: %s: %w", offset, err)
}
if minutes > 60 {
return time.Time{}, fmt.Errorf("invalid offset minutes: %d: %s", minutes, offset)
}
seconds, err := strconv.Atoi(offsetParts[2])
if err != nil {
return time.Time{}, fmt.Errorf("error parsing offset seconds: %s: %w", offset, err)
}View on GitHub (pinned to 7bedaf55a0)
Solutions
- Fix the offset string so hours are plain ASCII digits (e.g. '+03:30:00').
- Check for invisible characters (BOM, unicode minus '−' vs ASCII '-') in the timestamp and strip them.
- Regenerate the timestamp at the source using time.Format(time.RFC3339) instead of manual string building.
Example fix
// before
ParseISO8601("2024-01-02T15:04:05+0a:30:00") // error parsing offset hours
// after
ParseISO8601("2024-01-02T15:04:05+03:30:00") Defensive patterns
Strategy: validation
Validate before calling
func offsetHoursNumeric(ts string) bool {
i := strings.LastIndexAny(ts, "+-")
if i < 0 { return false }
parts := strings.Split(ts[i+1:], ":")
if len(parts) != 3 { return false }
_, err := strconv.Atoi(parts[0])
return err == nil
} Try / catch
tt, err := jsonx.ParseISO8601(s)
if err != nil {
if strings.Contains(err.Error(), "error parsing offset hours") {
return fmt.Errorf("malformed timestamp %q: %w", s, err)
}
return err
} Prevention
- Reject non-ASCII characters (unicode minus, BOM) in timestamp strings at the boundary.
- Never hand-build timestamp strings; use time.Format.
- Sanitize inputs copied from CSVs or spreadsheets.
When it happens
Trigger: ParseISO8601 on a timestamp whose offset hours field contains non-digits, e.g. '+0x:30:00', '+ 3:00:00', or a truncated/garbled offset.
Common situations: Corrupted or hand-edited timestamp strings; offsets copied with stray characters or unicode minus signs; data imported from spreadsheets/CSVs where '+' was stripped or replaced.
Related errors
- error parsing offset minutes: %s: %w
- error parsing offset seconds: %s: %w
- ISO8601: invalid timezone format: %s
- invalid offset format: %s
- invalid offset hours: %d: %s
AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30).
Data as JSON: /api/errors/11ba92bd6e4b2c22.
Report an issue: GitHub.