apache/cassandra · error · IllegalArgumentException

Timestamp format must be hh:mm:ss[.fffffffff]

Error message

Timestamp format must be hh:mm:ss[.fffffffff]

What it means

parseTime parses a CQL `time` literal string into nanos-since-midnight. This IllegalArgumentException is the generic format failure: the input is null, has no two colons in the expected hh:mm:ss arrangement, or has a malformed fractional-seconds part. It mirrors the driver-side parser for CQL time values.

Source

Thrown at src/java/org/apache/cassandra/cql3/functions/types/ParseUtils.java:399

     * @param str The string to parse.
     * @return A long value representing the number of nanoseconds since midnight.
     * @throws ParseException if the string cannot be parsed.
     * @see <a href="https://cassandra.apache.org/doc/cql3/CQL-2.2.html#usingtime">'Working with time'
     * section of CQL specification</a>
     */
    static long parseTime(String str) throws ParseException
    {
        String nanos_s;

        long hour;
        long minute;
        long second;
        long a_nanos = 0;

        String formatError = "Timestamp format must be hh:mm:ss[.fffffffff]";
        String zeros = "000000000";

        if (str == null) throw new IllegalArgumentException(formatError);
        str = str.trim();

        // Parse the time
        int firstColon = str.indexOf(':');
        int secondColon = str.indexOf(':', firstColon + 1);

        // Convert the time; default missing nanos
        if (firstColon > 0 && secondColon > 0 && secondColon < str.length() - 1)
        {
            int period = str.indexOf('.', secondColon + 1);
            hour = Integer.parseInt(str.substring(0, firstColon));
            if (hour < 0 || hour >= 24) throw new IllegalArgumentException("Hour out of bounds.");

            minute = Integer.parseInt(str.substring(firstColon + 1, secondColon));
            if (minute < 0 || minute >= 60) throw new IllegalArgumentException("Minute out of bounds.");

            if (period > 0 && period < str.length() - 1)
            {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Normalize the input to hh:mm:ss before parsing, e.g. expand "01:30" to "01:30:00".
  2. Strip/convert alternate formats (AM/PM, ISO-8601 durations) to hh:mm:ss[.fffffffff] with a pre-parser.
  3. Validate with a regex ^\d{1,2}:\d{2}:\d{2}(\.\d{1,9})?$ before calling parseTime.
  4. Catch IllegalArgumentException and surface a user-friendly message naming the expected format.

Example fix

// before
long nanos = ParseUtils.parseTime("01:30 PM"); // throws
// after
String normalized = "01:30 PM".replace(" PM", ""); // better: convert to 24h
long nanos = ParseUtils.parseTime(normalized + ":00"); // "13:30:00"
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern TIME = Pattern.compile("^\\d{1,2}:\\d{2}:\\d{2}(\\.\\d{1,9})?$");
if (str == null || !TIME.matcher(str.trim()).matches())
    throw new IllegalArgumentException("time must be hh:mm:ss[.fffffffff]: " + str);

Try / catch

try { return ParseUtils.parseTime(s); }
catch (IllegalArgumentException e) { throw new IllegalArgumentException("Invalid time literal '" + s + "': " + e.getMessage(), e); }

Prevention

When it happens

Trigger: Calling ParseUtils.parseTime(null); passing a string without colons (e.g. "1230"); only one colon ("12:30"); trailing colon with nothing after second colon ("12:30:"); a fractional part longer than 9 digits or starting with a non-digit; or a trailing dot like "12:30:30." (parsed via the ParseException path at the same message).

Common situations: Reading `time` columns from user input, CSV/JSON imports, or config files where values like "1:30" (single leading digit is fine, but "1h30m" or "01:30 PM" are not), ISO-8601 durations ("PT1H30M"), or "hh:mm" without seconds are supplied instead of hh:mm:ss[.fffffffff].

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/28a7dfeea7848c98. Report an issue: GitHub.