diff --git a/zppy/templates/cdscan_replacement.py b/zppy/templates/cdscan_replacement.py
new file mode 100644
index 00000000..7f5619d7
--- /dev/null
+++ b/zppy/templates/cdscan_replacement.py
@@ -0,0 +1,15 @@
+import sys
+
+import xcdat
+
+
+def cdscan_replacement(output_file, input_files):
+    dataset = xcdat.open_mfdataset(input_files)
+    # TODO: write to xml, not netCDF
+    dataset.to_netcdf(output_file)
+
+
+if __name__ == "__main__":
+    output_file = sys.argv[1]
+    input_files = sys.argv[2:]
+    cdscan_replacement(output_file, input_files)
diff --git a/zppy/templates/e3sm_diags.bash b/zppy/templates/e3sm_diags.bash
index cf568593..e6905951 100644
--- a/zppy/templates/e3sm_diags.bash
+++ b/zppy/templates/e3sm_diags.bash
@@ -108,7 +108,7 @@ create_links_ts()
     # xml file will cover the whole period from year1 to year2
     xml_name=${v}_${begin_year}01_${end_year}12.xml
     export CDMS_NO_MPI=true
-    cdscan -x ${xml_name} -f ${v}_files.txt
+    python cdscan_replacement.py ${xml_name} ${v}_files.txt
     if [ $? != 0 ]; then
       cd {{ scriptDir }}
       echo "ERROR (${error_num})" > {{ prefix }}.status
@@ -129,7 +129,7 @@ create_links_ts_rof()
   cd ${ts_rof_dir_destination}
   v="RIVER_DISCHARGE_OVER_LAND_LIQ"
   xml_name=${v}_${begin_year}01_${end_year}12.xml
-  cdscan -x ${xml_name} ${ts_rof_dir_source}/${v}_*.nc
+  python cdscan_replacement.py ${xml_name} ${ts_rof_dir_source}/${v}_*.nc
   if [ $? != 0 ]; then
     cd {{ scriptDir }}
     echo "ERROR (${error_num})" > {{ prefix }}.status
diff --git a/zppy/templates/global_time_series.bash b/zppy/templates/global_time_series.bash
index 8b69c7b0..096711d6 100644
--- a/zppy/templates/global_time_series.bash
+++ b/zppy/templates/global_time_series.bash
@@ -43,7 +43,7 @@ atmosphere_only=${atmosphere_only,,}
 echo 'Create xml files for atm'
 export CDMS_NO_MPI=true
 cd ${case_dir}/post/atm/glb/ts/monthly/${ts_num_years}yr
-cdscan -x glb.xml *.nc
+python cdscan_replacement.py glb.xml *.nc
 if [ $? != 0 ]; then
   cd {{ scriptDir }}
   echo 'ERROR (1)' > {{ prefix }}.status
@@ -67,7 +67,7 @@ if [[ ${atmosphere_only} == "false" ]]; then
     echo 'Create xml for for ocn'
     export CDMS_NO_MPI=true
     cd ${case_dir}/post/ocn/glb/ts/monthly/${ts_num_years}yr
-    cdscan -x glb.xml mpaso.glb*.nc
+    python cdscan_replacement.py glb.xml mpaso.glb*.nc
     if [ $? != 0 ]; then
       cd {{ scriptDir }}
       echo 'ERROR (3)' > {{ prefix }}.status
diff --git a/zppy/templates/readTS.py b/zppy/templates/readTS.py
index 5527e3e3..1d3cc59b 100644
--- a/zppy/templates/readTS.py
+++ b/zppy/templates/readTS.py
@@ -1,5 +1,4 @@
-import cdms2
-import cdutil
+import xcdat
 
 
 class TS(object):
@@ -7,7 +6,7 @@ def __init__(self, filename):
 
         self.filename = filename
 
-        self.f = cdms2.open(filename)
+        self.f = xcdat.open_dataset(filename)
 
     def __del__(self):
 
@@ -62,6 +61,6 @@ def globalAnnual(self, var):
             v = self.f(var)
 
             # Annual average
-            v = cdutil.YEAR(v)
+            v = self.f.temporal.group_average(v, "year")
 
         return v