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

  1. Fix the offset string so hours are plain ASCII digits (e.g. '+03:30:00').
  2. Check for invisible characters (BOM, unicode minus '−' vs ASCII '-') in the timestamp and strip them.
  3. 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

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


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/11ba92bd6e4b2c22. Report an issue: GitHub.