nautechsystems/nautilus_trader · error · anyhow::Error

Execution timestamp '{time_str}' was before Unix epoch

Error message

Execution timestamp '{time_str}' was before Unix epoch

What it means

datetime_to_unix_nanos converts a parsed IB timestamp to UnixNanos, which is a u64 count of nanoseconds since the Unix epoch. If the timestamp's nanosecond value is negative (i.e. the datetime predates 1970-01-01), the try_into::<u64> fails and this error is thrown since UnixNanos cannot represent pre-epoch times.

Source

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

            "Unrecognized execution timezone '{tz_str}' in '{time_str}'. Configure TWS / IB Gateway to emit a standard timezone (e.g. UTC)"
        )
    })?;
    let ambiguous = zone.to_ambiguous_timestamp(dt);
    match ambiguous.offset() {
        AmbiguousOffset::Unambiguous { .. } => Ok(ambiguous.unambiguous()?),
        // Fall-back fold: take the earliest instant (worst case ~1h skew).
        AmbiguousOffset::Fold { .. } => Ok(ambiguous.earlier()?),
        AmbiguousOffset::Gap { .. } => {
            anyhow::bail!("Execution timestamp '{time_str}' is non-existent in timezone '{tz_str}'")
        }
    }
}

fn datetime_to_unix_nanos(dt: Timestamp, time_str: &str) -> anyhow::Result<UnixNanos> {
    let nanos: u64 = dt
        .as_nanosecond()
        .try_into()
        .map_err(|_| anyhow::anyhow!("Execution timestamp '{time_str}' was before Unix epoch"))?;
    Ok(UnixNanos::new(nanos))
}

#[cfg(test)]
mod tests {
    use ibapi::{
        contracts::Contract,
        orders::{Action, ExecutionSide, Liquidity, Order, OrderStatusKind},
    };
    use nautilus_model::{
        enums::TrailingOffsetType,
        identifiers::{Symbol, Venue},
        instruments::{InstrumentAny, stubs::equity_aapl},
    };
    use rust_decimal::Decimal;

    use super::*;
    use crate::{

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the offending time_str in the error; a pre-epoch execution timestamp indicates corrupted input data that should be fixed at the source.
  2. Validate the parsed year is >= 1970 before conversion and reject such execution records early.
  3. Check machine clock/timezone configuration on the gateway host if timestamps are unexpectedly far in the past.

Example fix

// before
let nanos: u64 = dt
    .as_nanosecond()
    .try_into()
    .map_err(|_| anyhow::anyhow!("Execution timestamp '{time_str}' was before Unix epoch"))?;
// after
if dt.as_nanosecond() < 0 {
    anyhow::bail!("Execution timestamp '{time_str}' was before Unix epoch");
}
let nanos: u64 = dt
    .as_nanosecond()
    .try_into()
    .map_err(|_| anyhow::anyhow!("Execution timestamp '{time_str}' was before Unix epoch"))?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: reject pre-epoch timestamps before conversion
fn is_post_epoch(dt: &Timestamp) -> bool {
    dt.as_nanosecond() >= 0
}

Type guard

fn epoch_safe_nanos(dt: Timestamp) -> Option<u64> {
    u64::try_from(dt.as_nanosecond()).ok()
}

Try / catch

match u64::try_from(dt.as_nanosecond()) {
    Ok(nanos) => Ok(UnixNanos::new(nanos)),
    Err(_) => {
        tracing::error!("Execution timestamp '{time_str}' predates Unix epoch; skipping record");
        return Ok(());
    }
}

Prevention

When it happens

Trigger: parse_execution_time calls datetime_to_unix_nanos with a Timestamp before 1970-01-01 — e.g. a corrupted or misparsed execution time like "19691231 23:59:59" that still happens to match the naive format.

Common situations: Corrupt test/paper-trading data; year typos in synthetic fills; timezone localization shifting a near-epoch timestamp across the boundary; upstream system clocks badly misconfigured.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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