4
4
from collections .abc import Callable
5
5
from collections .abc import Mapping as MappingABC
6
6
import copy
7
- from datetime import datetime
7
+ import datetime
8
8
from glob import glob
9
9
import hashlib
10
10
import json
13
13
import os
14
14
import os .path as op
15
15
from pathlib import Path
16
+ import pydicom as dcm
17
+ from pydicom .tag import TagType
16
18
import re
17
19
import shutil
18
20
import stat
@@ -662,7 +664,7 @@ def get_datetime(date: str, time: str, *, microseconds: bool = True) -> str:
662
664
# add dummy microseconds if not available for strptime to parse
663
665
time += ".000000"
664
666
td = time + ":" + date
665
- datetime_str = datetime .strptime (td , "%H%M%S.%f:%Y%m%d" ).isoformat ()
667
+ datetime_str = datetime .datetime . strptime (td , "%H%M%S.%f:%Y%m%d" ).isoformat ()
666
668
if not microseconds :
667
669
datetime_str = datetime_str .split ("." , 1 )[0 ]
668
670
return datetime_str
@@ -686,7 +688,105 @@ def strptime_micr(date_string: str, fmt: str) -> datetime:
686
688
fmt = fmt [: - len (optional_micr )]
687
689
if re .search (r"\.\d+$" , date_string ):
688
690
fmt += ".%f"
689
- return datetime .strptime (date_string , fmt )
691
+ return datetime .datetime .strptime (date_string , fmt )
692
+
693
+
694
+ def datetime_utc_offset (datetime_obj : datetime , utc_offset : str ):
695
+ """set the datetime's tzinfo by parsing an utc offset string"""
696
+ sign , hours , minutes = re .match (r"([+\-]?)(\d{2})(\d{2})" , utc_offset ).groups ()
697
+ sign = - 1 if sign == '-' else 1
698
+ hours , minutes = int (hours ), int (minutes )
699
+ tzinfo = datetime .timezone (sign * datetime .timedelta (hours = hours , minutes = minutes ))
700
+ return datetime_obj .replace (tzinfo = tzinfo )
701
+
702
+ def strptime (datetime_string : str , fmts : list [str ]) -> datetime :
703
+ r"""
704
+ Try datetime.strptime on a list of formats returning the first successful attempt.
705
+
706
+ Parameters
707
+ ----------
708
+ datetime_string: str
709
+ Datetime string to parse
710
+ fmts: list[str]
711
+ List of format strings
712
+ """
713
+ datetime_str = datetime_string .strip ()
714
+ for fmt in fmts :
715
+ try :
716
+ #return datetime.datetime.strptime(datetime_str, fmt)
717
+ retval = datetime .datetime .strptime (datetime_str , fmt )
718
+ print (retval )
719
+ return retval
720
+ except ValueError :
721
+ pass
722
+ raise ValueError (f"Unable to parse datetime string: { datetime_str } " )
723
+
724
+ def strptime_bids (datetime_string : str ) -> datetime :
725
+ r"""
726
+ Create a datetime object from a bids datetime string.
727
+
728
+ Parameters
729
+ ----------
730
+ date_string: str
731
+ Datetime string to parse
732
+ """
733
+ # https://bids-specification.readthedocs.io/en/stable/common-principles.html#units
734
+ fmts = ["%Y-%m-%dT%H:%M:%S.%f%z" , "%Y-%m-%dT%H:%M:%S%z" , "%Y-%m-%dT%H:%M:%S.%f" , "%Y-%m-%dT%H:%M:%S" ]
735
+ datetime_obj = strptime (datetime_string , fmts )
736
+ return datetime_obj
737
+
738
+ def strptime_dcm_da_tm (dcm_data : dcm .Dataset , da_tag : TagType , tm_tag : TagType ) -> datetime :
739
+ r"""
740
+ Create a datetime object from a dicom DA tag and TM tag.
741
+
742
+ Parameters
743
+ ----------
744
+ dcm_data : dcm.FileDataset
745
+ DICOM with header, e.g., as read by pydicom.dcmread.
746
+ Objects with __getitem__ and have those keys with values properly formatted may also work
747
+ da_tag: str
748
+ Dicom tag with DA value representation
749
+ tm_tag: str
750
+ Dicom tag with TM value representation
751
+ """
752
+ # https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html
753
+ date_str = dcm_data [da_tag ].value
754
+ fmts = ["%Y%m%d" ,]
755
+ date = strptime (date_str , fmts )
756
+
757
+ time_str = dcm_data [tm_tag ].value
758
+ fmts = ["%H" , "%H%M" , "%H%M%S" , "%H%M%S.%f" ]
759
+ time = strptime (time_str , fmts )
760
+
761
+ datetime_obj = datetime .datetime .combine (date .date (), time .time ())
762
+
763
+ if (0x0008 , 0x0201 ) in dcm_data :
764
+ utc_offset = dcm_data [0x0008 , 0x0201 ].value
765
+ datetime_obj = datetime_utc_offset (datetime_obj , utc_offset ) if utc_offset else datetime_obj
766
+ return datetime_obj
767
+
768
+ def strptime_dcm_dt (dcm_data : dcm .Dataset , dt_tag : TagType ) -> datetime :
769
+ r"""
770
+ Create a datetime object from a dicom DT tag.
771
+
772
+ Parameters
773
+ ----------
774
+ dcm_data : dcm.FileDataset
775
+ DICOM with header, e.g., as read by pydicom.dcmread.
776
+ Objects with __getitem__ and have those keys with values properly formatted may also work
777
+ da_tag: str
778
+ Dicom tag with DT value representation
779
+ """
780
+ # https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html
781
+ datetime_str = dcm_data .get (dt_tag )
782
+ fmts = ["%Y%z" , "%Y%m%z" , "%Y%m%d%z" , "%Y%m%d%H%z" , "%Y%m%d%H%M%z" , "%Y%m%d%H%M%S%z" , "%Y%m%d%H%M%S.%f%z" ,
783
+ "%Y" , "%Y%m" , "%Y%m%d" , "%Y%m%d%H" , "%Y%m%d%H%M" , "%Y%m%d%H%M%S" , "%Y%m%d%H%M%S.%f" ]
784
+ datetime_obj = strptime (datetime_str , fmts )
785
+
786
+ if not datetime_obj .tzinfo and (0x0008 , 0x0201 ) in dcm_data :
787
+ utc_offset = dcm_data [0x0008 , 0x0201 ].value
788
+ datetime_obj = datetime_utc_offset (datetime_obj , utc_offset ) if utc_offset else datetime_obj
789
+ return datetime_obj
690
790
691
791
692
792
def remove_suffix (s : str , suf : str ) -> str :
0 commit comments