What’s new in 3.1.0 (Month XX, 2026)#

These are the changes in pandas 3.1.0. See Release notes for a full changelog including other versions of pandas.

Enhancements#

enhancement1#

enhancement2#

Other enhancements#

  • Period now supports f-string formatting via __format__, e.g. f"{period:%Y-%m}" (GH 48536)

  • DataFrameGroupBy.agg() now allows for the provided func to return a NumPy array (GH 63957)

  • Timestamp.round(), Timestamp.floor(), and Timestamp.ceil() now officially accept Timedelta arguments (GH 63687)

  • ExtensionArray.map() now calls ExtensionArray._cast_pointwise_result() to retain the dtype backend, e.g. Arrow-backed arrays now preserve their Arrow dtype through map (GH 57189, GH 62164)

  • read_csv() now supports dtype="complex64" and dtype="complex128" with the C engine, enabling round-tripping of complex-number columns written by DataFrame.to_csv() (GH 9379)

  • Added ExtensionArray.count() (GH 64450)

  • Added Index.replace() method to support value replacement functionality similar to Series.replace() (GH 19495)

  • Display formatting for float sequences in DataFrame cells now respects the display.precision option (GH 60503).

  • Improved the precision of float parsing in read_csv() (GH 64395)

  • Improved the string repr of pd.core.arrays.SparseArray (GH 64547)

  • Improved type inference of comparison and arithmetic operators on Series and DataFrame for static type checkers (e.g. ser == "a" is now inferred as Series instead of Any) (GH 40762)

  • MSVC is no longer required to build on Windows, and build errors when using the MinGW compiler have been fixed (GH 63160)

Notable bug fixes#

These are bug fixes that might have notable behavior changes.

notable_bug_fix1#

notable_bug_fix2#

Backwards incompatible API changes#

Increased minimum versions for dependencies#

Some minimum supported versions of dependencies were updated. If installed, we now require:

Package

Minimum Version

Required

Changed

X

X

For optional libraries the general recommendation is to use the latest version. The following table lists the lowest version per library that is currently being tested throughout the development of pandas. Optional libraries below the lowest tested version may still work, but are not considered supported.

Package

Minimum Version

Changed

X

See Dependencies and Optional dependencies for more.

Other API changes#

Deprecations#

Performance improvements#

Bug fixes#

Categorical#

  • Bug in Categorical.__repr__() where the values and categories lines could exceed display.width (GH 12066)

  • Bug in Categorical.map() where mapping with a defaultdict and na_action=None would bypass the default factory by using dict.get, causing NA values to be replaced with NaN instead of the mapper’s default value (GH 62710)

  • Bug in CategoricalIndex.union() and CategoricalIndex.intersection() giving incorrect results when the two indexes have the same unordered categories in different orders (GH 55335)

  • Bug in Index.fillna() raising TypeError when filling with a tuple value (e.g. on object-dtype or CategoricalIndex with tuple categories) (GH 37681)

Datetimelike#

  • Bug in DatetimeIndex constructor raising ValueError when passing equivalent but not equal frequencies (e.g. QS-FEB vs QS-MAY) (GH 61086)

  • Bug in DatetimeIndex raising AttributeError when comparing against Arrow date types (date32, date64) (GH 62051)

  • Bug in Timestamp constructor where passing np.str_ objects would fail in Cython string parsing (GH 48974)

  • Bug in Timestamp constructor where strings with a negative year of fewer than 4 digits (e.g. "-111-01-01") silently dropped the leading "-" and were parsed as a positive year; BC dates with 1-4 digit years now parse correctly, matching numpy.datetime64 (GH 55954)

  • Bug in Timestamp constructor, Timedelta constructor, to_datetime(), and to_timedelta() with non-round float input and unit failing to raise when the value is just outside the representable bounds (GH 57366)

  • Bug in api.types.infer_dtype() returning "date" or "mixed" instead of "datetime" / "timedelta" for lists of Timestamp/Timedelta values mixed with pd.NA (GH 53023)

  • Bug in date_range() where inclusive="left" and inclusive="right" returned a single-element result instead of empty when start equals end (GH 55293)

  • Bug in date_range() where inclusive parameter failed to filter endpoints when only start and periods or end and periods were specified (GH 46331)

  • Bug in date_range() where periods=1 with offsets that disallow n=0 (e.g. offsets.LastWeekOfMonth, offsets.FY5253) raised ValueError (GH 41563)

  • Bug in date_range() where calendar-based offsets (e.g. MS, ME, QS, YS) could exclude the last offset boundary when end’s time-of-day was earlier than start’s (GH 35342)

  • Bug in to_datetime() and to_timedelta() on ARM platforms where round float values outside the int64 domain (e.g. float(2**63)) could silently produce incorrect results instead of raising (GH 64619)

  • Bug in to_datetime() and to_timedelta() where uint64 values greater than int64 max silently overflowed instead of raising OutOfBoundsDatetime or OutOfBoundsTimedelta (GH 60677)

  • Bug in to_datetime() when using a low time resolution unit, higher resolution in origin is now preserved instead of silently dropped (e.g. unit="D" with microsecond precision origin) (GH 63419)

  • Bug in DataFrame.replace() and Series.replace() raising AssertionError instead of OutOfBoundsDatetime when replacing with a datetime value outside the datetime64[ns] range (GH 61671)

  • Bug in DataFrame.to_string() and Series.to_string() where na_rep was ignored for datetime and timedelta columns, always displaying NaT (GH 55426)

  • Bug in DatetimeArray.isin() and TimedeltaArray.isin() where mismatched resolutions could silently truncate finer-resolution values, leading to false matches (GH 64545)

  • Bug in adding non-nano DatetimeIndex with non-vectorized offsets (e.g. CustomBusinessDay, CustomBusinessMonthEnd) having a sub-unit offset parameter incorrectly truncating the result or raising AttributeError (GH 56586)

  • Bug in subtracting BusinessHour (or CustomBusinessHour) from a Timestamp giving incorrect results when the subtraction would land exactly on the business-hour opening time (GH 33682)

Timedelta#

  • Bug in TimedeltaIndex.resolution raising when the index has no frequency (GH 65186)

  • Bug in DateOffset where DateOffset(1) and DateOffset(days=1) returned different results near daylight saving time transitions (GH 61862)

  • Bug in Timedelta constructor where keyword arguments (e.g. days=365000) that exceeded nanosecond int64 bounds raised OutOfBoundsTimedelta instead of falling back to a coarser resolution (GH 46587)

  • Bug in to_timedelta() where passing np.str_ objects would fail in Cython string parsing (GH 48974)

Timezones#

Numeric#

Conversion#

  • Bug in DataFrame constructor where NaT in a TimedeltaIndex row was incorrectly inferred as datetime64 instead of timedelta64 (GH 23985)

  • Bug in DataFrame constructor where constructing from a list of uniform-dtype arrays (e.g. pyarrow, CategoricalDtype, nullable dtypes) lost the dtype (GH 49593)

  • Bug in pd.array() silently converting NaN to a nonsensical integer when given float data containing NaN and a NumPy integer dtype (GH 41724)

  • Fixed pandas.array() to preserve mask information when converting NumPy masked arrays, converting masked values to missing values (GH 63879).

  • Fixed bug in DataFrame.from_records() where exclude was ignored when data was an iterator and nrows=0 (GH 63774)

Strings#

  • Bug in DataFrame.replace() with regex=True mutating the underlying StringArray when the replacement value was not a string (GH 57733)

Interval#

  • Bug in IntervalArray and IntervalIndex constructors unnecessarily upcasting sub-64-bit numeric dtypes (e.g. float32, int32) to 64-bit (GH 45412)

Indexing#

Missing#

MultiIndex#

I/O#

Period#

  • Bug in Period constructor where passing np.str_ objects would fail in Cython string parsing (GH 48974)

  • Bug in Period.strftime() where unknown format directives (e.g. "%Q") silently produced platform-dependent output and crashed the Python process on Windows; an Invalid format string ValueError is now raised on all platforms (GH 53562)

Plotting#

Groupby/resample/rolling#

Reshaping#

  • Bug in merge() where merging on a MultiIndex containing NaN values mapped NaN keys to the last level value instead of NaN (GH 64492)

  • Bug in DataFrame.pivot_table() with margins=True raising TypeError when values has an ExtensionDtype that cannot hold NA (e.g. IntervalDtype with an integer subtype) and no columns were specified (GH 55484)

  • Bug in Index.union() where the result could be unsorted when both inputs were monotonic increasing but disjoint, when sort was not False (GH 54646)

  • In pivot_table(), when values is empty, the aggregation will be computed on a Series of all NA values (GH 46475)

Sparse#

  • Bug in SparseArray.astype() where converting a datetime64 SparseArray with NaT fill value to "Sparse[int64]" silently replaced the fill value with 0 instead of iNaT (GH 49631)

  • Bug in indexing a SparseArray with an out-of-bounds integer with the value of the length of the array returning the fill value instead of raising an IndexError (GH 64183).

ExtensionArray#

Styler#

Other#

Contributors#