nautechsystems/nautilus_trader · error · ValueError

pandas is required for nanosecond-precision datetimes

Error message

pandas is required for nanosecond-precision datetimes

What it means

unix_nanos_to_dt converts a UNIX-ns integer to a UTC datetime. Without pandas it falls back to stdlib datetime, which caps precision at microseconds; if the timestamp has a sub-microsecond remainder (nanos % 1000 != 0) it refuses to silently round-trip and lose precision, requiring pandas (pd.Timestamp supports true ns). Timestamps that are exact microsecond multiples still work without pandas.

Source

Thrown at python/nautilus_trader/core/datetime.py:66

]

_NANOS_PER_MICROSECOND = 1_000
_NANOS_PER_SECOND = 1_000_000_000
_SECONDS_PER_DAY = 86_400
_UNIX_EPOCH = datetime(1970, 1, 1, tzinfo=UTC)


def unix_nanos_to_dt(nanos: int) -> Any:
    """
    Return the UTC datetime for the given UNIX timestamp in nanoseconds.
    """
    try:
        import pandas as pd
    except ImportError:
        seconds, nanos_remainder = divmod(int(nanos), _NANOS_PER_SECOND)
        microseconds, nanos_remainder = divmod(nanos_remainder, _NANOS_PER_MICROSECOND)
        if nanos_remainder:
            raise ValueError("pandas is required for nanosecond-precision datetimes") from None

        return _UNIX_EPOCH + timedelta(seconds=seconds, microseconds=microseconds)

    return pd.Timestamp(int(nanos), unit="ns", tz="UTC")


def dt_to_unix_nanos(value: Any) -> int:
    """
    Return the UNIX timestamp in nanoseconds for the given datetime-like value.
    """
    if value is None:
        raise ValueError("value must not be None")

    try:
        import pandas as pd
    except ImportError:
        if isinstance(value, int):
            return value

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Install pandas (it is a core nautilus_trader dependency in normal installs): pip install pandas
  2. If sub-microsecond precision is genuinely irrelevant, truncate to the microsecond boundary yourself: unix_nanos_to_dt(nanos - nanos % 1_000)
  3. Pass microsecond-aligned timestamps (ns % 1000 == 0) when pandas cannot be installed

Example fix

# before (no pandas installed)
unix_nanos_to_dt(1_700_000_000_123_456_789)
# ValueError: pandas is required for nanosecond-precision datetimes

# after
import pandas as pd  # env now has pandas
unix_nanos_to_dt(1_700_000_000_123_456_789)
# or, if truncation is acceptable:
unix_nanos_to_dt(1_700_000_000_123_456_789 - 789)
Defensive patterns

Strategy: validation

Validate before calling

try:
    import pandas  # noqa: F401
    HAS_PANDAS = True
except ImportError:
    HAS_PANDAS = False

if not HAS_PANDAS and nanos % 1_000 != 0:
    nanos = nanos - nanos % 1_000  # truncate to microsecond boundary (explicit choice)
dt = unix_nanos_to_dt(nanos)

Try / catch

try:
    dt = unix_nanos_to_dt(nanos)
except ValueError as e:
    if 'pandas is required' in str(e):
        dt = unix_nanos_to_dt(nanos - nanos % 1_000)  # degrade to us precision
    else:
        raise

Prevention

When it happens

Trigger: unix_nanos_to_dt(1_700_000_000_123_456_789) in an environment where 'import pandas' fails — the 789ns remainder trips the guard. Any ns value not divisible by 1000 hits it.

Common situations: Minimal deployments of nautilus_trader.core helpers without the pandas extra; timestamps from high-resolution clocks (raw ns since epoch) rather than exchange timestamps aligned to microseconds.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/6018389d306c8e4e. Report an issue: GitHub.