{"record":{"id":"4a8bc317dd19aac6","repo":"google/gson","slug":"failed-parsing-as-sql-time-at-path","errorCode":null,"errorMessage":"Failed parsing '{}' as SQL Time; at path {}","messagePattern":"Failed parsing '(.+?)' as SQL Time; at path (.+?)","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/sql/SqlTimeTypeAdapter.java","lineNumber":70,"sourceCode":"\n  private final DateFormat format = new SimpleDateFormat(\"hh:mm:ss a\");\n\n  private SqlTimeTypeAdapter() {}\n\n  @Override\n  public Time read(JsonReader in) throws IOException {\n    if (in.peek() == JsonToken.NULL) {\n      in.nextNull();\n      return null;\n    }\n    String s = in.nextString();\n    synchronized (this) {\n      TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone\n      try {\n        Date date = format.parse(s);\n        return new Time(date.getTime());\n      } catch (ParseException e) {\n        throw new JsonSyntaxException(\n            \"Failed parsing '\" + s + \"' as SQL Time; at path \" + in.getPreviousPath(), e);\n      } finally {\n        format.setTimeZone(originalTimeZone); // Restore the original time zone\n      }\n    }\n  }\n\n  @Override\n  public void write(JsonWriter out, Time value) throws IOException {\n    if (value == null) {\n      out.nullValue();\n      return;\n    }\n    String timeString;\n    synchronized (this) {\n      timeString = format.format(value);\n    }\n    out.value(timeString);","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/sql/SqlTimeTypeAdapter.java#L52-L88","documentation":"Thrown by Gson's SqlTimeTypeAdapter when its SimpleDateFormat(\"hh:mm:ss a\") fails to parse the JSON string into java.sql.Time. The default format expects a 12-hour clock with AM/PM marker in the adapter locale (e.g. \"12:00:00 PM\"); ISO times (\"00:00:00\"), 24-hour strings, or locale-mismatched AM/PM tokens cause ParseException wrapped as JsonSyntaxException.","triggerScenarios":"Deserializing a field of type java.sql.Time from a JSON string that does not match \"hh:mm:ss a\" in the running locale: e.g. \"13:30:00\" (24-hour), \"13:30\" (no seconds/AM-PM), \"1330\", or AM/PM tokens in a locale whose DateFormatSymbols differ.","commonSituations":"Producers using ISO 8601 time or 24-hour strings; servers in locales where AM/PM markers are localized differently (e.g. non-English locales); fields mistakenly typed as java.sql.Time when the data is a full timestamp; timezone shifts.","solutions":["Produce JSON strings matching \"hh:mm:ss a\" in the JVM locale, OR switch the field type to java.time.LocalTime / String and convert explicitly.","Register a custom TypeAdapter<java.sql.Time> using SimpleDateFormat(\"HH:mm:ss\") for 24-hour ISO input.","Pin the format locale to Locale.US (or the producer's locale) to avoid AM/PM token mismatches.","Sanitize the input (convert 24-hour to 12-hour with AM/PM) before Gson if you cannot change the producer."],"exampleFix":"// before\npublic class Schedule { public java.sql.Time opensAt; }\n// JSON: {\"opensAt\":\"13:30:00\"} -> fails (expects \"hh:mm:ss a\")\n\n// after: custom adapter for 24-hour ISO times\nGson g = new GsonBuilder()\n  .registerTypeAdapter(java.sql.Time.class, new TypeAdapter<java.sql.Time>() {\n    private final DateFormat f = new SimpleDateFormat(\"HH:mm:ss\", Locale.US);\n    public java.sql.Time read(JsonReader in) throws IOException {\n      try { return new java.sql.Time(f.parse(in.nextString()).getTime()); }\n      catch (ParseException e) { throw new JsonSyntaxException(e); }\n    }\n    public void write(JsonWriter out, java.sql.Time v) throws IOException { out.value(f.format(v)); }\n  }).create();","handlingStrategy":"validation","validationCode":"// validate 24-hour ISO time, or accept 'hh:mm:ss a'\nprivate static final Pattern HHMMSS = Pattern.compile(\"^\\\\d{2}:\\\\d{2}:\\\\d{2}$\");\nString raw = jsonNode.get(\"opensAt\").getAsString();\nif (raw == null || !HHMMSS.matcher(raw).matches()) {\n  throw new IllegalArgumentException(\"Not 'HH:mm:ss': \" + raw);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return gson.fromJson(json, Schedule.class);\n} catch (JsonSyntaxException e) {\n  if (e.getMessage().contains(\"as SQL Time\")) {\n    // switch to a 24-hour adapter for java.sql.Time\n    throw new IllegalArgumentException(\"Bad SQL Time format\", e);\n  }\n  throw e;\n}","preventionTips":["Register a custom TypeAdapter<java.sql.Time> with the actual time format and locale.","Pin the format locale (Locale.US) to avoid localized AM/PM tokens.","Prefer java.time.LocalTime for new code.","Contract-test time round-trip in non-English locales."],"tags":["gson","date-parsing","sql-time","simple-date-format","locale","json-syntax-exception"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}