Repository: nipy/heudiconv

Issue:
Use AcquisitionTime for acq_time column of scans tsv files
<!-- DO NOT DELETE THIS! 
This template is used to facilitate issue resolution.
All text in <!-> tags will not be displayed.
-->

### Summary
<!-- If you are having conversion troubles, please share as much
relevant information as possible. This includes, but is not limited to:
- log of conversion
- heuristic
-->

It looks like heudiconv [uses ContentTime](https://github.com/nipy/heudiconv/blob/75f2850f7f07a95ff5875aba1dfd76c09e4be201/heudiconv/bids.py#L408-L411) in the scans tsv files instead of AcquisitionTime, although I think that AcquisitionTime would be more appropriate (i.e., closer to the actual start of the scan).

Quoting @pvelasco in https://github.com/physiopy/phys2bids/pull/219#issuecomment-626899271: 
>>In dicoms, SeriesTime, InstanceCreationTime, and ContentTime are very similar, but AcquisitionTime is generally ~20 seconds earlier than the rest. We need to determine which time is closest to the scanner's trigger pulse.

>From some documentation I found from Siemens on image reconstruction:

>>AcquisitionTime: The Time the acquisition of data started.

>From an answer given by Chris Roden (dcm2niix):

>>Instance Creation Time 0008,0013 initially reflects the time an image leaves a parallel processing reconstructor, so it has a variable delay with regards to the acquisition time. Acquisition Time is more meaningful for data.

>So, if the reconstruction involves something more than a straight FFT (i.e., GRAPPA, SENSE, etc.), that will explain the ~20 sec delay you find between the AcquisitionTime and the other times.
>If I remember correctly, for Siemens scanners, the "scanner trigger" is sent at the time of the excitation pulse of the first slice of each (collected) volume. So the very first trigger will be sent just a few milliseconds before the first chunk of data for the first slice for the first volume is acquired (AcquisitionTime).

This issue is related to #447.


Discussion:

Patch:
diff --git a/heudiconv/bids.py b/heudiconv/bids.py
index ce8ab4c..4647358 100644
--- a/heudiconv/bids.py
+++ b/heudiconv/bids.py
@@ -404,10 +404,10 @@ def get_formatted_scans_key_row(dcm_fn):
     """
     dcm_data = dcm.read_file(dcm_fn, stop_before_pixels=True, force=True)
     # we need to store filenames and acquisition times
-    # parse date and time and get it into isoformat
+    # parse date and time of start of run acquisition and get it into isoformat
     try:
-        date = dcm_data.ContentDate
-        time = dcm_data.ContentTime
+        date = dcm_data.AcquisitionDate
+        time = dcm_data.AcquisitionTime
         acq_time = get_datetime(date, time)
     except (AttributeError, ValueError) as exc:
         lgr.warning("Failed to get date/time for the content: %s", str(exc))


Test patch:
diff --git a/heudiconv/tests/test_main.py b/heudiconv/tests/test_main.py
index 924295c..e696b99 100644
--- a/heudiconv/tests/test_main.py
+++ b/heudiconv/tests/test_main.py
@@ -171,7 +171,7 @@ def test_get_formatted_scans_key_row():
 
     row1 = get_formatted_scans_key_row(dcm_fn)
     assert len(row1) == 3
-    assert row1[0] == '2016-10-14T09:26:36.693000'
+    assert row1[0] == '2016-10-14T09:26:34.692500'
     assert row1[1] == 'n/a'
     prandstr1 = row1[2]