google/gson · error · IllegalArgumentException

No time zone indicator

Error message

No time zone indicator

What it means

Thrown internally by UtcDateTypeAdapter's ISO-8601 parser when the date string has no characters left at the position where a time-zone indicator ('Z', '+', or '-') is expected. The adapter requires every parsed date to carry an explicit timezone; a bare date like "2024-01-01T00:00:00" without a zone is rejected. This IllegalArgumentException is caught and converted into a ParseException, which read() then wraps as a JsonParseException.

Source

Thrown at extras/src/main/java/com/google/gson/typeadapters/UtcDateTypeAdapter.java:193

          offset += 1;
        }
        // second and milliseconds can be optional
        if (date.length() > offset) {
          char c = date.charAt(offset);
          if (c != 'Z' && c != '+' && c != '-') {
            seconds = parseInt(date, offset, offset += 2);
            // milliseconds can be optional in the format
            if (checkOffset(date, offset, '.')) {
              milliseconds = parseInt(date, offset += 1, offset += 3);
            }
          }
        }
      }

      // extract timezone
      String timezoneId;
      if (date.length() <= offset) {
        throw new IllegalArgumentException("No time zone indicator");
      }
      char timezoneIndicator = date.charAt(offset);
      if (timezoneIndicator == '+' || timezoneIndicator == '-') {
        String timezoneOffset = date.substring(offset);
        timezoneId = GMT_ID + timezoneOffset;
        offset += timezoneOffset.length();
      } else if (timezoneIndicator == 'Z') {
        timezoneId = GMT_ID;
        offset += 1;
      } else {
        throw new IndexOutOfBoundsException("Invalid time zone indicator " + timezoneIndicator);
      }

      TimeZone timezone = TimeZone.getTimeZone(timezoneId);
      if (!timezone.getID().equals(timezoneId)) {
        throw new IndexOutOfBoundsException();
      }

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Ensure the date string includes an explicit timezone: append 'Z' for UTC or '+HH:mm'/'-HH:mm' for an offset (e.g. "2024-01-01T12:00:00Z").
  2. Normalize date strings on the producer to always emit a timezone before sending.
  3. If you cannot change the input, register a custom TypeAdapter<Date> that defaults omitted zones to UTC instead of using UtcDateTypeAdapter.
  4. Pre-validate the string with a regex like .*[ZzZ+-]\d\d:?\d\d$ before parsing.

Example fix

// before
String json = "\"2024-01-01T12:00:00\""; // no timezone indicator
Date d = gson.fromJson(json, Date.class); // throws (via JsonParseException)

// after
String json = "\"2024-01-01T12:00:00Z\"";
Date d = gson.fromJson(json, Date.class);
Defensive patterns

Strategy: validation

Validate before calling

// Validate the date string has a timezone indicator before parsing
static void requireTimezone(String date) {
  // last meaningful char must be Z, +, or -; or end with offset like +HH:mm
  if (!date.matches(".*[Zz]$|.*/[+-]\\d{2}:?\\d{2}$")) {
    throw new IllegalArgumentException("Date missing timezone: " + date);
  }
}

Type guard

static boolean hasTimezoneIndicator(String date) {
  if (date == null || date.isEmpty()) return false;
  char last = date.charAt(date.length() - 1);
  if (last == 'Z' || last == 'z') return true;
  // tolerate trailing offset +HH:mm / -HH:mm
  return date.matches(".*[+-]\\d{2}:?\\d{2}$");
}

Try / catch

try {
  Date d = gson.fromJson(json, Date.class);
} catch (JsonParseException e) {
  Throwable c = e.getCause();
  if (c != null && c.getMessage() != null && c.getMessage().contains("No time zone indicator")) {
    // retry after appending 'Z' if UTC was intended, or reject
  } else throw e;
}

Prevention

When it happens

Trigger: Parsing a date string that ends right after the time component with no zone, e.g. "2024-01-01T12:00:00"; a date-only string "20240101" where the optional time section is absent and nothing follows; truncated input. Surfaced to the Gson caller as JsonParseException during fromJson when the UtcDateTypeAdapter is registered.

Common situations: Backend sends ISO-8601 without timezone (assumed local/UTC implicitly); mixing date formats where some payloads omit the zone; data from systems that produce "local" timestamps; trimming trailing characters during transport.

Related errors


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