prestodb/presto · error · IllegalArgumentException

Invalid timestamp '%s'

Error message

Invalid timestamp '%s'

What it means

DateTimeUtils.timestampHasTimeZone parses a timestamp literal to determine whether it carries a time-zone offset. If the string cannot be parsed by either the timestamp-with-tz or timestamp-without-tz formatter, the original RuntimeException is swallowed and replaced with an IllegalArgumentException whose message embeds the offending value.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/util/DateTimeUtils.java:283

    {
        return LEGACY_TIMESTAMP_WITHOUT_TIME_ZONE_FORMATTER.withChronology(getChronology(timeZoneKey)).print(timestamp);
    }

    public static boolean timestampHasTimeZone(String value)
    {
        try {
            try {
                TIMESTAMP_WITH_TIME_ZONE_FORMATTER.parseMillis(value);
                return true;
            }
            catch (RuntimeException e) {
                // `.withZoneUTC()` makes `timestampHasTimeZone` return value independent of JVM zone
                TIMESTAMP_WITHOUT_TIME_ZONE_FORMATTER.withZoneUTC().parseMillis(value);
                return false;
            }
        }
        catch (RuntimeException e) {
            throw new IllegalArgumentException(format("Invalid timestamp '%s'", value));
        }
    }

    private static final DateTimeFormatter TIME_FORMATTER;
    private static final DateTimeFormatter TIME_WITH_TIME_ZONE_FORMATTER;

    static {
        DateTimeParser[] timeWithoutTimeZoneParser = {
                DateTimeFormat.forPattern("H:m").getParser(),
                DateTimeFormat.forPattern("H:m:s").getParser(),
                DateTimeFormat.forPattern("H:m:s.SSS").getParser()};
        DateTimePrinter timeWithoutTimeZonePrinter = DateTimeFormat.forPattern("HH:mm:ss.SSS").getPrinter();
        TIME_FORMATTER = new DateTimeFormatterBuilder().append(timeWithoutTimeZonePrinter, timeWithoutTimeZoneParser).toFormatter().withZoneUTC();

        DateTimeParser[] timeWithTimeZoneParser = {
                DateTimeFormat.forPattern("H:mZ").getParser(),
                DateTimeFormat.forPattern("H:m Z").getParser(),
                DateTimeFormat.forPattern("H:m:sZ").getParser(),

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Correct the literal to Presto's timestamp format, e.g. '2024-01-31 12:00:00.000' or with offset '2024-01-31 12:00:00 +01:00'
  2. Use try_cast(value AS TIMESTAMP) to get NULL instead of a failure, then inspect NULLs
  3. Pre-normalize strings with date_parse/date_format or from_iso8601_timestamp before classifying
  4. Check that the value has no stray whitespace, 'T' separators, or unsupported timezone names (use numeric offsets)

Example fix

// before
long x = DateTimeUtils.timestampHasTimeZone("2024/01/31");
// after
long x = DateTimeUtils.timestampHasTimeZone("2024-01-31 00:00:00");
Defensive patterns

Strategy: try-catch

Validate before calling

boolean ok = value != null && value.matches("\\d{1,4}-\\d{2}-\\d{2}([ T]\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,3})?)?)?([+-]\\d{2}:?\\d{2})? *$");

Try / catch

try { DateTimeUtils.timestampHasTimeZone(value); } catch (IllegalArgumentException e) { log.warn("Bad timestamp literal: {}", value); /* fallback: use try_cast or reject row */ }

Prevention

When it happens

Trigger: Passing a malformed timestamp string to any SQL path that must classify a timestamp literal (e.g. parsing 'TIMESTAMP' literals or casting strings during query planning) — anything that does not match the expected timestamp format such as "2024-13-45 99:00:00" or free-form text.

Common situations: Hand-written SQL with typos in date literals; data imported with locale-specific formats (DD/MM/YYYY vs YYYY-MM-DD); strings with trailing garbage or missing components; epoch-style or ISO-8601-with-'T' formats the legacy Joda formatter does not accept.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/9bb8f05d327e7ce5. Report an issue: GitHub.