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
- 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.
- Reset the date/time format settings in TWS / IB Gateway API configuration to the default.
- 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
- Keep TWS / IB Gateway date-time format settings at defaults
- Validate timestamp shape in message normalization before the adapter
- Log raw execution rows so malformed timestamps are diagnosable
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid expiry format: {}
- Negative nanosecond timestamp from: {timestamp}
- Timestamp out of range for candle at {}
- Unrecognized execution timezone '{tz_str}' in '{time_str}'.
- Execution timestamp '{time_str}' was before Unix epoch
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/270c8575d03c49a9.
Report an issue: GitHub.