nibabel icon indicating copy to clipboard operation
nibabel copied to clipboard

patient_birth_date dtype should be signed integer in nibabel.ecat

Open mcsitter opened this issue 3 months ago • 1 comments

Hi,

I noticed that in nibabel/ecat.py, the patient_birth_date field is defined as:

('patient_birth_date', np.uint32),

This causes incorrect date interpretations, for example producing birth dates in the future rather than before the Unix epoch. It seems this field should be a signed integer (np.int32) to correctly handle dates.

At least in the ECAT files I have, patient_birth_date must be signed integers to interpret dates correctly. Tools like Vinci read these files correctly when treated as signed.

Example:

import numpy as np
import datetime, calendar

# 19 Dec 1915 at midnight UTC
ts = calendar.timegm(datetime.datetime(1915, 12, 19).timetuple())

# Structured array with wrong dtype
dtype_wrong = [('patient_birth_date', np.uint32)]
arr_wrong = np.array([(ts,)], dtype=dtype_wrong)

# Structured array with correct dtype
dtype_right = [('patient_birth_date', np.int32)]
arr_right = np.array([(ts,)], dtype=dtype_right)

# Convert back to datetime
dt_wrong = datetime.datetime.utcfromtimestamp(arr_wrong['patient_birth_date'][0])
dt_right = datetime.datetime.utcfromtimestamp(arr_right['patient_birth_date'][0])

print("Unsigned (wrong):", arr_wrong['patient_birth_date'][0], "->", dt_wrong)
print("Signed (correct):", arr_right['patient_birth_date'][0], "->", dt_right)

Example output:

Unsigned (wrong): 2589690496 -> 2052-01-24 06:28:16
Signed (correct): -1705276800 -> 1915-12-19 00:00:00

Changing it to np.int32 fixes this issue. I can also prepare a PR for this update if that’s helpful.

Thanks!

mcsitter avatar Sep 19 '25 09:09 mcsitter

Yes, a PR would be helpful. Do you know what versions of ECAT your files are? This might need to change based on the version.

effigies avatar Oct 21 '25 13:10 effigies