Structured arrays, datetimes and string dtypes

Record-like arrays, calendar arithmetic with datetime64, and the fixed-width string type that quietly truncates your data.

Structured arrays

A structured array stores records with named fields in one contiguous buffer. It is the closest NumPy gets to a table, and fields are accessed by name and keep their own dtypes.

dt = np.dtype([("name", "U10"), ("age", "i4"), ("score", "f8")])
rows = np.array([("ada", 36, 91.5), ("bob", 41, 78.0)], dtype=dt)

rows["age"]                       # array([36, 41], dtype=int32)
rows[rows["age"] > 38]            # boolean mask over a field
rows["score"].mean()              # 84.75
np.sort(rows, order="score")      # sort records by a field

rows[0]                           # a record, not a view
rows[0]["age"] = 37               # writes through to the buffer
rows["score"] = rows["score"] + 1 # update one field across all records
dtype codeMeaningExample
i4, f8Integers and floatsCompact numeric fields
U10Unicode string, fixed width 10Short labels
S10Bytes string, fixed width 10Legacy binary data
M8[D]Datetime64, day resolutionCalendar dates
m8[s]Timedelta64, second resolutionDurations
OPython objectAnything else, at a cost

Datetime64 arithmetic

d = np.array(["2026-01-01", "2026-02-01"], dtype="datetime64[D]")

d + np.timedelta64(30, "D")          # array with 30 days added
d[1] - d[0]                          # numpy.timedelta64(31,'D')
(d[1] - d[0]) / np.timedelta64(1, "D")   # 31.0, a plain float
d.astype("datetime64[M]")            # truncate to the month

np.datetime64("2026-09-18T12:00")    # an instant
np.datetime64("now")                 # current time, second resolution

# a date axis for a plot or a group-by in seconds
stamps = np.array(["2026-01-01T00:00", "2026-01-01T01:30"], dtype="datetime64[m]")
stamps.astype("datetime64[h]")
  • The unit in the dtype decides precision: converting to a coarser unit truncates rather than rounds.
  • NaT is the missing-value marker; np.isnat(d) tests for it.
  • Subtracting two datetimes gives a timedelta, not a number; divide by a timedelta of the unit you want.
  • Time zones are not represented: convert to UTC before storing.

String dtypes and their traps

s = np.array(["abc", "de"], dtype="U3")   # fixed width, space padded
s.astype("U10")                 # widening is safe
np.char.upper(s)                # vectorised string operations
np.char.add(s, "_x")
np.char.str_len(s)

np.array(["long text"], dtype="U3")   # silently truncated to 'lon'
s.astype(object)                # unlimited length, much slower
⚠️
A fixed-width string dtype truncates on assignment without an error. If your array might contain names, URLs or free text, choose a generous width or use dtype=object — and prefer pandas or Arrow for real text data.

FAQ

Structured array or pandas DataFrame?
Use a structured array for compact binary records that stay in NumPy, especially when exported with np.save. Use a DataFrame for labelled analysis, joins and mixed missing values.
Why is datetime64 giving me an error on month arithmetic?
Arithmetic requires a timedelta, and adding months is not a fixed duration. Add np.timedelta64(30, "D"), or convert to months and increment the integer.

File I/O: save, load, npz and memory-mapped arrays Sorting, searching and set operations

Last refreshed 2026-09-18.