Skip to content

Fix timezone-aware DatetimeIndex converting to an object array - #5870

Draft
somaz94 wants to merge 3 commits into
plotly:mainfrom
somaz94:fix-tz-aware-datetimeindex
Draft

somaz94 wants to merge 3 commits into
plotly:mainfrom
somaz94:fix-tz-aware-datetimeindex

Conversation

@somaz94

@somaz94 somaz94 commented Nov 4, 2026 •

Copy link
Copy Markdown

Link to issue

Closes #5864

Description of change

A timezone-aware DatetimeIndex passes through nw.from_native unchanged, so np.array turned it into an object array of Timestamps that were then deep-copied and encoded one at a time. copy_to_readonly_numpy_array now converts a pandas Index to a Series first, as MarcoGorelli suggested, so it takes the existing Series path, which already removes the time zone.

This covers every Index, so I compared 17 index types against main. On pandas 3.0.2 only the timezone-aware DatetimeIndex output changes. On pandas 1.5.3 a nullable Int64 index also changes, from an object array to float64 with NaN, as a Series of that type already does.

This changes the output for these indexes so that it matches a timezone-aware Series. With the json engine, 2024-03-30T12:00:00+01:00 becomes 2024-03-30T12:00:00.000000, and NaT is written as "NaT" rather than null. The same applies to text and customdata, where a reader could see the difference. I compared the JSON but did not compare rendering in a browser.

The "NaT" output is the behavior reported in #5829, which the draft #5831 proposes to change to null. If that lands, these indexes follow it without further changes here.

Demo

100,000 points on Python 3.12 and pandas 3.0.2 with orjson installed, best of five runs:

before, tz-aware index   object           Figure() 0.285 s  to_json() 0.353 s
after,  tz-aware index   datetime64[us]   Figure() 0.019 s  to_json() 0.008 s
after,  tz-aware series  datetime64[us]   Figure() 0.019 s  to_json() 0.007 s

Testing strategy

I added a test that a timezone-aware DatetimeIndex comes out as datetime64 with its wall-clock values; it fails without the change. tests/test_core, tests/test_plotly_utils, tests/test_io, tests/test_optional and both test_init checks pass locally.

AI assistance

I used Claude Code for the investigation, the change and the test. I reviewed the result myself and will answer review questions myself.

Guidelines

somaz94 added a commit to somaz94/somaz94 that referenced this pull request Nov 4, 2026
@MarcoGorelli

Copy link
Copy Markdown
Contributor

thanks @somaz94

this is one solution - I think another could be to do something like

if isinstance(x, pd.Index):
    x = x.to_series()

?

then it just goes down the existing Series path. That might be cleaner and special-casey. fancy trying it and seeing if it also fixes the issue?

@somaz94

somaz94 commented Nov 5, 2026

Copy link
Copy Markdown
Author

Thanks, that works and it is cleaner, so I switched to it in 63c1771. A timezone-aware DatetimeIndex now takes the Series path and comes out as datetime64. Since this now applies to every Index, I compared 17 index types against main: on pandas 3.0.2 only the timezone-aware DatetimeIndex output changes, and on pandas 1.5.3 a nullable Int64 index also goes from an object array to float64 with NaN. Timing is the same as the previous version. The workflows have not run on this PR yet, could someone approve them?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Timezone-aware pandas DatetimeIndex as x makes figure creation and to_json() ~30x slower

2 participants