kataras/iris · error

ISO8601: missing timezone offset

Error message

ISO8601: missing timezone offset

What it means

This error means the ISO8601 timestamp string handed to the parser has no timezone offset at all (no +HH:MM / -HH:MM suffix). The library's parseWithOffset path is only used when the string is expected to carry an offset, so finding none is treated as a hard parse failure rather than falling back to a zone-less time. It indicates the datetime part parsed OK positionally but the required offset signature ('+' or '-') is absent.

Source

Thrown at x/jsonx/iso8601.go:173

				tt, err = time.Parse(ISO8601ZUTCOffsetLayoutWithoutMicroseconds, s)
			}
		}
	} else if s[len(s)-1] == 'Z' {
		tt, err = time.Parse(ISO8601LayoutWithTimezone, s)
	} else {
		tt, err = time.Parse(ISO8601Layout, s)
	}

	if err != nil {
		return ISO8601{}, fmt.Errorf("ISO8601: %w", err)
	}
	return ISO8601(tt), nil
}

func parseWithOffset(s string) (time.Time, error) {
	idx := strings.LastIndexFunc(s, startUTCOffsetIndexFunc)
	if idx == -1 {
		return time.Time{}, fmt.Errorf("ISO8601: missing timezone offset")
	}

	offsetText := s[idx:]
	secondsEastUTC, err := parseOffsetToSeconds(offsetText)
	if err != nil {
		return time.Time{}, err
	}

	loc, ok := fixedEastUTCLocations[secondsEastUTC]
	if !ok {
		loc = time.FixedZone("", secondsEastUTC)
	}

	return time.ParseInLocation(ISO8601ZUTCOffsetLayoutWithoutMicroseconds, s, loc)
}

func parseOffsetToSeconds(offsetText string) (int, error) {
	if len(offsetText) < 6 {

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Append a valid UTC offset to the input string, e.g. '2024-01-02T15:04:05' -> '2024-01-02T15:04:05+00:00' (or use the 'Z' suffix form '2024-01-02T15:04:05Z' so ParseISO8601 takes the Z-layout branch).
  2. If zone-less input is expected/allowed, do not route it through ParseISO8601 expecting an offset; pre-normalize the string (regex check for [+-]HH:MM) before calling, or parse with time.Parse(ISO8601Layout, s) directly.
  3. Fix upstream producers (API clients, DB column type 'timestamptz', serialization layer) so timestamps always include the offset.
  4. If the string is truncated, verify no middleware/logging pipeline is cutting the tail (min length for offset form is 25 chars: '2006-01-02T15:04:05+07:00').

Example fix

// before
var t jsonx.ISO8601
err := t.UnmarshalJSON([]byte("2024-01-02T15:04:05")) // ISO8601: missing timezone offset
// after
err := t.UnmarshalJSON([]byte("2024-01-02T15:04:05+00:00")) // ok
// or use the Z form:
err = t.UnmarshalJSON([]byte("2024-01-02T15:04:05Z"))
Defensive patterns

Strategy: validation

Validate before calling

var isoOffsetRe = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}:\d{2}|Z)$`)
func hasTimezone(s string) bool { return isoOffsetRe.MatchString(s) }
// call jsonx.ParseISO8601 only if hasTimezone(s); otherwise normalize by appending "+00:00"

Type guard

func isOffsetForm(s string) bool {
	i := strings.LastIndexAny(s, "+-")
	return i > 18 && len(s)-i == 6
}

Try / catch

tt, err := jsonx.ParseISO8601(s)
if err != nil {
	if strings.Contains(err.Error(), "missing timezone offset") {
		// fall back to naive layout
		t0, perr := time.Parse(jsonx.ISO8601Layout, s)
		if perr == nil {
			tt = jsonx.ISO8601(t0)
			err = nil
		}
	}
	if err != nil {
		return fmt.Errorf("parse timestamp %q: %w", s, err)
	}
}

Prevention

When it happens

Trigger: Calling jsonx.ParseISO8601 (or ISO8601.UnmarshalJSON / ISO8601.Scan) with a string that reaches parseWithOffset yet contains no '+' or '-' rune: e.g. '2024-01-02T15:04:05' with a code path that assumes an offset, or a truncated string like '2024-01-02T15:04:05' where the offset was stripped by upstream normalization.

Common situations: Frontends or third-party APIs sending naive local datetimes (no zone) into structs with jsonx.ISO8601 fields; database drivers returning 'timestamp without time zone' strings scanned into ISO8601; config files or CSV imports with datetime strings lacking the offset; truncation of the tail of a timestamp during logging/serialization.

Related errors


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