{"record":{"id":"6018389d306c8e4e","repo":"nautechsystems/nautilus_trader","slug":"pandas-is-required-for-nanosecond-precision-dateti","errorCode":null,"errorMessage":"pandas is required for nanosecond-precision datetimes","messagePattern":"pandas is required for nanosecond-precision datetimes","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/nautilus_trader/core/datetime.py","lineNumber":66,"sourceCode":"]\n\n_NANOS_PER_MICROSECOND = 1_000\n_NANOS_PER_SECOND = 1_000_000_000\n_SECONDS_PER_DAY = 86_400\n_UNIX_EPOCH = datetime(1970, 1, 1, tzinfo=UTC)\n\n\ndef unix_nanos_to_dt(nanos: int) -> Any:\n    \"\"\"\n    Return the UTC datetime for the given UNIX timestamp in nanoseconds.\n    \"\"\"\n    try:\n        import pandas as pd\n    except ImportError:\n        seconds, nanos_remainder = divmod(int(nanos), _NANOS_PER_SECOND)\n        microseconds, nanos_remainder = divmod(nanos_remainder, _NANOS_PER_MICROSECOND)\n        if nanos_remainder:\n            raise ValueError(\"pandas is required for nanosecond-precision datetimes\") from None\n\n        return _UNIX_EPOCH + timedelta(seconds=seconds, microseconds=microseconds)\n\n    return pd.Timestamp(int(nanos), unit=\"ns\", tz=\"UTC\")\n\n\ndef dt_to_unix_nanos(value: Any) -> int:\n    \"\"\"\n    Return the UNIX timestamp in nanoseconds for the given datetime-like value.\n    \"\"\"\n    if value is None:\n        raise ValueError(\"value must not be None\")\n\n    try:\n        import pandas as pd\n    except ImportError:\n        if isinstance(value, int):\n            return value","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/python/nautilus_trader/core/datetime.py#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Install pandas (it is a core nautilus_trader dependency in normal installs): pip install pandas","If sub-microsecond precision is genuinely irrelevant, truncate to the microsecond boundary yourself: unix_nanos_to_dt(nanos - nanos % 1_000)","Pass microsecond-aligned timestamps (ns % 1000 == 0) when pandas cannot be installed"],"exampleFix":"# before (no pandas installed)\nunix_nanos_to_dt(1_700_000_000_123_456_789)\n# ValueError: pandas is required for nanosecond-precision datetimes\n\n# after\nimport pandas as pd  # env now has pandas\nunix_nanos_to_dt(1_700_000_000_123_456_789)\n# or, if truncation is acceptable:\nunix_nanos_to_dt(1_700_000_000_123_456_789 - 789)","handlingStrategy":"validation","validationCode":"try:\n    import pandas  # noqa: F401\n    HAS_PANDAS = True\nexcept ImportError:\n    HAS_PANDAS = False\n\nif not HAS_PANDAS and nanos % 1_000 != 0:\n    nanos = nanos - nanos % 1_000  # truncate to microsecond boundary (explicit choice)\ndt = unix_nanos_to_dt(nanos)","typeGuard":null,"tryCatchPattern":"try:\n    dt = unix_nanos_to_dt(nanos)\nexcept ValueError as e:\n    if 'pandas is required' in str(e):\n        dt = unix_nanos_to_dt(nanos - nanos % 1_000)  # degrade to us precision\n    else:\n        raise","preventionTips":["Install pandas in any deployment touching nautilus_trader datetime helpers","Keep a HAS_PANDAS feature flag in apps that must run without it","Align generated timestamps to microsecond boundaries if ns fidelity is unused"],"tags":["python","datetime","pandas","precision","nanoseconds","missing-dependency"],"backgroundTag":"missing-optional-dependency","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}