nautechsystems/nautilus_trader · error

Negative timestamp: {unix_timestamp_ns}

Error message

Negative timestamp: {unix_timestamp_ns}

What it means

After computing midnight-UTC of the adjusted weekday, last_weekday_nanos converts the signed nanosecond timestamp to u64 for UnixNanos; a negative value means the date falls before the UNIX epoch (1970-01-01), which UnixNanos cannot represent. The library throws it because UnixNanos is an unsigned u64 nanosecond count.

Source

Thrown at crates/core/src/datetime.rs:521

    // Calculate the offset in days for closest weekday (Mon-Fri)
    let offset = match current_weekday {
        1..=5 => 0, // Monday to Friday, no adjustment needed
        6 => 1,     // Saturday, adjust to previous Friday
        _ => 2,     // Sunday, adjust to previous Friday
    };
    // Calculate last closest weekday
    let last_closest = date.checked_sub(Span::new().days(offset))?;

    // Convert to UNIX nanoseconds
    let unix_timestamp_ns = last_closest
        .at(0, 0, 0, 0)
        .to_zoned(TimeZone::UTC)?
        .timestamp()
        .as_nanosecond();

    let ns_u64 = u64::try_from(unix_timestamp_ns)
        .map_err(|_| anyhow::anyhow!("Negative timestamp: {unix_timestamp_ns}"))?;
    Ok(UnixNanos::from(ns_u64))
}

/// Check whether the given UNIX nanoseconds timestamp is within the last 24 hours.
///
/// # Errors
///
/// Returns an error if the timestamp is invalid.
pub fn is_within_last_24_hours(timestamp_ns: UnixNanos) -> anyhow::Result<bool> {
    // Use the time seam so the comparison is deterministic under
    // `simulation` + `cfg(madsim)` and we avoid a wall-clock call that
    // would otherwise bypass the DST contract.
    let timestamp_ns = timestamp_ns.as_u64();
    let now_ns = nanos_since_unix_epoch();

    // Future timestamps are not within the last 24 hours
    if timestamp_ns > now_ns {
        return Ok(false);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure input dates are on or after 1970-01-01; clamp or reject earlier dates at the call site.
  2. If pre-epoch timestamps are genuinely needed, use a signed timestamp type (jiff Timestamp / i64 nanos) instead of UnixNanos.
  3. Check for accidental negative years caused by sign or argument-order mistakes.

Example fix

// before
let ns = last_weekday_nanos(1969, 7, 20)?; // pre-epoch -> negative timestamp
// after
debug_assert!(year >= 1970);
let ns = last_weekday_nanos(1970, 1, 2)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: reject pre-epoch dates before calling
if year < 1970 { return Err(anyhow!("date {year} is before UNIX epoch")); }

Try / catch

let ns = last_weekday_nanos(year, month, day)
    .with_context(|| format!("week day anchor for {year}-{month:02}-{day:02}"))?;

Prevention

When it happens

Trigger: Calling last_weekday_nanos with any date before 1970-01-01, e.g. birthdates, historical data anchors like (1969, 12, 31), or years far in the past such as (1900, 1, 15).

Common situations: Using the function for historical calendar computations rather than market timestamps; a year sign error (-2024 instead of 2024); migrating legacy datasets with pre-epoch dates into nautilus types.

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/379af1118bd7c1bd. Report an issue: GitHub.