nautechsystems/nautilus_trader · error · anyhow::Error

Failed to parse execution timestamp '{time_str}': {e}

Error message

Failed to parse execution timestamp '{time_str}': {e}

What it means

parse_execution_time converts IB execution timestamps into Unix nanos. For the hyphenated, space-less form (e.g. "20250225-15:15:00", always UTC), it normalizes the string and parses with the fixed format "%Y%m%d %H:%M:%S". If the string doesn't match that format (wrong ordering, missing seconds, alphabetic garbage), the strptime fails and this error is thrown.

Source

Thrown at crates/adapters/interactive_brokers/src/execution/parse.rs:402

/// Timezones are resolved through Jiff's bundled IANA tz database, so any
/// region abbreviation or name that IB stamps the execution with (e.g. `MET`,
/// `EST`, `America/New_York`) is honored, matching the v1 pandas-based parser.
/// This matters because some IB accounts (e.g. European paper accounts) report a
/// server timezone such as `MET` that the gateway cannot be coerced out of.
///
/// # Errors
///
/// Returns an error if the timestamp is malformed, the timezone is
/// unrecognized, or the local time is non-existent (a DST spring-forward gap).
/// DST fall-back folds resolve to the earliest matching instant.
pub fn parse_execution_time(time_str: &str) -> anyhow::Result<UnixNanos> {
    const NAIVE_FORMAT: &str = "%Y%m%d %H:%M:%S";

    // Hyphenated, space-less form (e.g. "20250225-15:15:00") is always UTC.
    if !time_str.contains(' ') {
        let normalized = time_str.replace('-', " ");
        let dt = DateTime::strptime(NAIVE_FORMAT, &normalized).map_err(|e| {
            anyhow::anyhow!("Failed to parse execution timestamp '{time_str}': {e}")
        })?;
        return datetime_to_unix_nanos(Offset::UTC.to_timestamp(dt)?, time_str);
    }

    // Split into at most three parts: date, time, and optional timezone token.
    // The timezone token itself never contains a space, so `splitn(3, ' ')`
    // correctly groups IANA names such as "America/New_York".
    let mut parts = time_str.splitn(3, ' ');
    let (Some(date), Some(time)) = (parts.next(), parts.next()) else {
        anyhow::bail!("Invalid execution time format: {time_str}");
    };
    let tz_str = parts.next().unwrap_or("").trim();

    let naive_str = format!("{date} {time}");
    let dt = DateTime::strptime(NAIVE_FORMAT, &naive_str)
        .map_err(|e| anyhow::anyhow!("Failed to parse execution timestamp '{time_str}': {e}"))?;

    let utc = if tz_str.is_empty() {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the offending time_str (it is included in the message) and compare against expected IB formats like 20250225, 15:15:00 or 20250225-15:15:00.
  2. Reset the date/time format settings in TWS / IB Gateway API configuration to the default.
  3. Upgrade the ibapi crate / adapter if your IB API version emits a new timestamp format, or pre-normalize the string before passing it on.

Example fix

// before
let dt = DateTime::strptime(NAIVE_FORMAT, &normalized).map_err(|e| {
    anyhow::anyhow!("Failed to parse execution timestamp '{time_str}': {e}")
})?;
// after
let normalized = time_str
    .replace('-', " ")
    .replace('T', " ");
let dt = DateTime::strptime(NAIVE_FORMAT, &normalized).map_err(|e| {
    anyhow::anyhow!("Failed to parse execution timestamp '{time_str}': {e}")
})?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate the hyphenated IB timestamp before parsing
fn looks_like_ib_hyphenated(s: &str) -> bool {
    let b = s.as_bytes();
    b.len() == 19
        && b[8] == b'-'
        && b.iter().enumerate().all(|(i, c)| {
            i == 8 || c.is_ascii_digit() || i == 13 || i == 16 || c == b':' == false
        })
}

Type guard

fn is_valid_execution_time(time_str: &str) -> bool {
    time_str.len() == 19 || (time_str.len() >= 17 && time_str.contains(' '))
}

Try / catch

match parse_execution_time(time_str) {
    Ok(nanos) => nanos,
    Err(e) => {
        tracing::error!("Skipping execution record with bad timestamp: {e}");
        return Ok(());
    }
}

Prevention

When it happens

Trigger: Called from parse_historical_fill_report, handle_execution_data, build_pending_combo_fill, or generate_leg_fill with a time_str containing no space but not matching %Y%m%d-%H:%M:%S — e.g. "2025-02-25 15:15:00", "20250225 15:15", or empty string.

Common situations: Custom IB time format settings in TWS/Gateway; API version differences in the execution report format; timestamps from report files edited or reformatted by other tooling.

Understand the failure class

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/270c8575d03c49a9. Report an issue: GitHub.