google/gson · error · IndexOutOfBoundsException

Mismatching time zone indicator: " + timezoneId + " given, r

Error message

Mismatching time zone indicator: " + timezoneId + " given, resolves to " + timezone.getID()

What it means

ISO8601Utils parses a +/- offset and constructs TimeZone.getTimeZone('GMT'+offset). The JDK silently falls back to GMT for unknown/invalid IDs, so Gson compares the returned ID to the requested one and throws IndexOutOfBoundsException when they differ even after stripping colons, indicating the offset was invalid (e.g. '+99:99').

Source

Thrown at gson/src/main/java/com/google/gson/internal/bind/util/ISO8601Utils.java:270

          // 18-Jun-2015, tatu: Looks like offsets only work from GMT, not UTC...
          //    not sure why, but that's the way it looks. Further, Javadocs for
          //    `java.util.TimeZone` specifically instruct use of GMT as base for
          //    custom timezones... odd.
          String timezoneId = "GMT" + timezoneOffset;
          // String timezoneId = "UTC" + timezoneOffset;

          timezone = TimeZone.getTimeZone(timezoneId);

          String act = timezone.getID();
          if (!act.equals(timezoneId)) {
            /* 22-Jan-2015, tatu: Looks like canonical version has colons, but we may be given
             *    one without. If so, don't sweat.
             *   Yes, very inefficient. Hopefully not hit often.
             *   If it becomes a perf problem, add 'loose' comparison instead.
             */
            String cleaned = act.replace(":", "");
            if (!cleaned.equals(timezoneId)) {
              throw new IndexOutOfBoundsException(
                  "Mismatching time zone indicator: "
                      + timezoneId
                      + " given, resolves to "
                      + timezone.getID());
            }
          }
        }
      } else {
        throw new IndexOutOfBoundsException(
            "Invalid time zone indicator '" + timezoneIndicator + "'");
      }

      Calendar calendar = new GregorianCalendar(timezone);
      calendar.setLenient(false);
      calendar.set(Calendar.YEAR, year);
      calendar.set(Calendar.MONTH, month - 1);
      calendar.set(Calendar.DAY_OF_MONTH, day);
      calendar.set(Calendar.HOUR_OF_DAY, hour);

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Correct the offset in the source to a valid ±HH:MM in the range -12:00 .. +14:00.
  2. Pre-validate/normalize the offset before passing to Gson.
  3. Register a custom date adapter that maps invalid offsets to a default zone.

Example fix

// before
Date d = gson.fromJson("\"2024-01-01T00:00:00+25:00\"", Date.class);

// after
String fixed = source.replaceAll("([+\\-])([0-9]{2}):([0-9]{2})$", m -> /* clamp to +/-14:00 */ "+00:00");
Date d = gson.fromJson('"' + fixed + '"', Date.class);
Defensive patterns

Strategy: validation

Validate before calling

boolean isValidOffset(String iso) {
  java.util.regex.Matcher m = java.util.regex.Pattern.compile("([+\\-])(\\d{2}):(\\d{2})$").matcher(iso == null ? "" : iso);
  if (!m.find()) return true; // not an explicit offset
  int hh = Integer.parseInt(m.group(2)), mm = Integer.parseInt(m.group(3));
  return hh <= 14 && mm < 60;
}

Type guard

static boolean hasPlausibleOffset(String iso) {
  return iso != null && iso.matches(".*[+\\-](0[0-9]|1[0-4]):[0-5][0-9]$");
}

Try / catch

try {
  Date d = gson.fromJson(json, Date.class);
} catch (JsonSyntaxException e) {
  // if 'Mismatching time zone indicator', reject or clamp offset and retry
}

Prevention

When it happens

Trigger: A date string whose numeric offset is out of range such as '+25:00', '-13:00', or '+99:99', causing the JDK to substitute GMT.

Common situations: Corrupt producer data, hand-built strings, timezone offsets with wrong sign or magnitude, or a serialization bug upstream.

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/d2da281b38e49eff.json. Report an issue: GitHub.