{"record":{"id":"96ed0ae899936e1d","repo":"nautechsystems/nautilus_trader","slug":"negative-nanosecond-timestamp-from-timestamp","errorCode":null,"errorMessage":"Negative nanosecond timestamp from: {timestamp}","messagePattern":"Negative nanosecond timestamp from: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":396,"sourceCode":"\n/// Converts a millisecond-based timestamp (as returned by OKX) into\n/// [`UnixNanos`].\n#[must_use]\npub fn parse_millisecond_timestamp(timestamp_ms: u64) -> UnixNanos {\n    UnixNanos::from(timestamp_ms * NANOSECONDS_IN_MILLISECOND)\n}\n\n/// Parses an RFC 3339 timestamp string into [`UnixNanos`].\n///\n/// # Errors\n///\n/// Returns an error if the string is not a valid RFC 3339 datetime or if the\n/// timestamp cannot be represented in nanoseconds.\npub fn parse_rfc3339_timestamp(timestamp: &str) -> anyhow::Result<UnixNanos> {\n    let dt = timestamp.parse::<Timestamp>()?;\n    let nanos = dt.as_nanosecond();\n    if nanos < 0 {\n        anyhow::bail!(\"Negative nanosecond timestamp from: {timestamp}\");\n    }\n    let nanos = u64::try_from(nanos)\n        .with_context(|| format!(\"Timestamp is outside the UnixNanos range: {timestamp}\"))?;\n    Ok(UnixNanos::from(nanos))\n}\n\n/// Converts a textual price to a [`Price`] using the given precision.\n///\n/// # Errors\n///\n/// Returns an error if the string fails to parse into `Decimal` or if the number\n/// of decimal places exceeds `precision`.\npub fn parse_price(value: &str, precision: u8) -> anyhow::Result<Price> {\n    let decimal = Decimal::from_str(value)?;\n    Price::from_decimal_dp(decimal, precision).map_err(Into::into)\n}\n\n/// Converts a textual quantity to a [`Quantity`].","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L378-L414","documentation":"parse_rfc3339_timestamp parses an RFC 3339 datetime string to UnixNanos. If the parsed timestamp precedes the Unix epoch, the nanosecond count is negative and cannot be stored in the u64-backed UnixNanos, so the function bails with the offending string included in the message.","triggerScenarios":"Passing a pre-1970 date string (e.g. '1969-12-31T23:59:59Z') to parse_rfc3339_timestamp, typically from exchange fields like creation or listing timestamps.","commonSituations":"Venue APIs returning zero or placeholder dates that get formatted as pre-epoch times; timezone bugs producing negative offsets before epoch; historical data loaders reading legacy records.","solutions":["Validate/clamp the timestamp to >= 1970-01-01T00:00:00Z before parsing","Fix the upstream data source emitting the pre-epoch value","Use a signed time representation if pre-epoch timestamps are legitimately required"],"exampleFix":"// before\nlet ts = parse_rfc3339_timestamp(raw)?;\n// after\nlet dt = raw.parse::<Timestamp>()?;\nif dt.as_nanosecond() < 0 { dt = EPOCH; } // clamp before parsing\nlet ts = parse_rfc3339_timestamp(raw)?;","handlingStrategy":"validation","validationCode":"// Rust\nfn is_epoch_or_later(rfc3339: &str) -> bool {\n    rfc3339.parse::<time::OffsetDateTime>()\n        .map(|dt| dt.unix_timestamp_nanos() >= 0)\n        .unwrap_or(false)\n}\nassert!(is_epoch_or_later(ts_str));","typeGuard":null,"tryCatchPattern":"// Rust\nlet ts = match parse_rfc3339_timestamp(raw) {\n    Err(e) if e.to_string().contains(\"Negative nanosecond\") => {\n        warn!(\"pre-epoch timestamp {raw}; defaulting to epoch\");\n        UnixNanos::default()\n    }\n    other => other?,\n};","preventionTips":["Clamp or reject zero/placeholder dates from venue payloads","Check timezone handling when formatting timestamps","Validate historical data timestamps before ingestion"],"tags":["rust","timestamp","parsing","pre-epoch"],"backgroundTag":"invalid-date-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}