diff --git a/src/cdi.h b/src/cdi.h
index e844d3d64a7187c3a466d31106a4c31d8cb51888..95097e410d81e9a304ff2b40da527f26a5a9b483 100644
--- a/src/cdi.h
+++ b/src/cdi.h
@@ -1344,9 +1344,11 @@ int streamOpenReadQuery(const char *path, const CdiQuery *query);
 
 #include "cdi_datetime.h"
 
-void taxisDefRdatetime(int taxisID, CdiDateTime rdatetime);
+void taxisDefRdatetime(int taxisID, CdiDateTime rDateTime);
 CdiDateTime taxisInqRdatetime(int taxisID);
-void taxisDefVdatetime(int taxisID, CdiDateTime vdatetime);
+void taxisDefFdatetime(int taxisID, CdiDateTime fDateTime);
+CdiDateTime taxisInqFdatetime(int taxisID);
+void taxisDefVdatetime(int taxisID, CdiDateTime vDateTime);
 CdiDateTime taxisInqVdatetime(int taxisID);
 void taxisDefVdatetimeBounds(int taxisID, CdiDateTime vdatetime_lb, CdiDateTime vdatetime_ub);
 void taxisInqVdatetimeBounds(int taxisID, CdiDateTime *vdatetime_lb, CdiDateTime *vdatetime_ub);
diff --git a/src/grb_write.c b/src/grb_write.c
index 815cc7239a5108894568cb696f605b4a4b5a5b91..be820cde1c6f25ece348c4a16d45624cc2182250 100644
--- a/src/grb_write.c
+++ b/src/grb_write.c
@@ -24,7 +24,7 @@
 #include "namespace.h"
 
 static size_t
-grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID, int date, int time,
+grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID, CdiDateTime vDateTime,
           int tsteptype, int numavg, size_t datasize, const void *data, size_t nmiss, void **gribbuffer, int comptype,
           void *gribContainers)
 {
@@ -36,7 +36,7 @@ grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gr
       size_t gribbuffersize = datasize * 4 + 3000;
       *gribbuffer = Malloc(gribbuffersize);
 
-      nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg, datasize, data,
+      nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID, vDateTime, tsteptype, numavg, datasize, data,
                              nmiss, *gribbuffer, gribbuffersize);
     }
   else
@@ -58,7 +58,7 @@ grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gr
         }
 
       size_t gribbuffersize;
-      nbytes = gribapiEncode(varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg, (long) datasize, datap, nmiss,
+      nbytes = gribapiEncode(varID, levelID, vlistID, gridID, zaxisID, vDateTime, tsteptype, numavg, (long) datasize, datap, nmiss,
                              gribbuffer, &gribbuffersize, comptype, gribContainer);
 
       if (memtype == MEMTYPE_FLOAT) Free((void *) datap);
@@ -378,8 +378,7 @@ grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, co
   const int zaxisID = vlistInqVarZaxis(vlistID, varID);
   const int tsteptype = vlistInqVarTsteptype(vlistID, varID);
   const int tsID = streamptr->curTsID;
-  const int date = (int) cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
-  const int time = cdiTime_get(streamptr->tsteps[tsID].taxis.vdatetime.time);
+  const CdiDateTime vDateTime = streamptr->tsteps[tsID].taxis.vdatetime;
   const int numavg = (tsteptype == TSTEP_AVG) ? streamptr->tsteps[tsID].taxis.numavg : 0;
   int comptype = streamptr->comptype;
 
@@ -397,7 +396,7 @@ grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, co
     }
 
   void *gribbuffer = NULL;
-  size_t nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg, datasize,
+  size_t nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, vDateTime, tsteptype, numavg, datasize,
                             data, nmiss, &gribbuffer, comptype, streamptr->gribContainers);
 
   if (filetype == CDI_FILETYPE_GRB && (comptype == CDI_COMPRESS_SZIP || comptype == CDI_COMPRESS_AEC))
@@ -424,8 +423,8 @@ grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, co
         const double level = zaxisInqLevel(zaxisID, levelID);
 
         FDB_Keys fdbKeys;
-        snprintf(fdbKeys.date, sizeof(fdbKeys.date), "%d", (int) cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date));
-        snprintf(fdbKeys.time, sizeof(fdbKeys.time), "%04d", (short)(cdiTime_get(streamptr->tsteps[tsID].taxis.vdatetime.time) / 100));
+        snprintf(fdbKeys.date, sizeof(fdbKeys.date), "%d", (int) cdiDate_get(vDateTime.date));
+        snprintf(fdbKeys.time, sizeof(fdbKeys.time), "%04d", (short)(cdiTime_get(vDateTime.time) / 100));
         snprintf(fdbKeys.param, sizeof(fdbKeys.param), "%d", get_fdb_param(vlistInqVarParam(vlistID, varID)));
         const bool isML = (zaxisType == ZAXIS_HYBRID || zaxisType == ZAXIS_HYBRID_HALF);
         snprintf(fdbKeys.levtype, sizeof(fdbKeys.levtype), "%s", isML ? "ml" : "sfc");
diff --git a/src/stream_cdf_i.c b/src/stream_cdf_i.c
index 42d7ee81d089394f6da4447b7af487dc31a7cc71..e9fc24c9d8720a524a6645e7d3ef9002c7c1c509 100644
--- a/src/stream_cdf_i.c
+++ b/src/stream_cdf_i.c
@@ -187,13 +187,9 @@ set_forecast_time(const char *timestr, taxis_t *taxis)
 {
   const size_t len = strlen(timestr);
   if (len != 0)
-    {
-      const CdiDateTime datetime = scan_time_string(timestr);
-      taxis->fdate = (int) cdiDate_get(datetime.date);
-      taxis->ftime = cdiTime_get(datetime.time);
-    }
+    taxis->fDateTime = scan_time_string(timestr);
   else
-    taxis->fdate = taxis->ftime = 0;
+    cdiDateTime_init(&(taxis->fDateTime));
 }
 
 static int
diff --git a/src/stream_cgribex.c b/src/stream_cgribex.c
index e92f77d02b873ae943d209d439baaf24e3376ab1..c9ca3ba1e14414b12e782bf063b1e6888a43e5f7 100644
--- a/src/stream_cgribex.c
+++ b/src/stream_cgribex.c
@@ -847,17 +847,12 @@ cgribexScanTimestep1(stream_t *streamptr)
           fcast = cgribexTimeIsFC(isec1);
           taxis->unit = cgribexGetTimeUnit(isec1);
           taxis->rdatetime = cdiDateTime_set(gribRefDate(isec1), gribRefTime(isec1));
-          taxis->sdate = cdiDate_get(sDateTime.date);
-          taxis->stime = cdiTime_get(sDateTime.time);
+          taxis->sDateTime = sDateTime;
           taxis->vdatetime = vDateTime;
         }
       else
         {
-          if (cdiDateTime_isLT(sDateTime, cdiDateTime_set(taxis->sdate, taxis->stime)))
-            {
-              taxis->sdate = cdiDate_get(sDateTime.date);
-              taxis->stime = cdiTime_get(sDateTime.time);
-            }
+          if (cdiDateTime_isLT(sDateTime, taxis->sDateTime)) taxis->sDateTime = sDateTime;
 
           compvar_t compVar = cgribexVarSet(param, level1, level2, leveltype, ISEC1_TimeRange);
           record_t *records = streamptr->tsteps[tsID].records;
@@ -1015,16 +1010,11 @@ cgribexScanTimestep2(stream_t *streamptr)
             }
           taxis->unit = cgribexGetTimeUnit(isec1);
           taxis->vdatetime = vDateTime;
-          taxis->sdate = cdiDate_get(sDateTime.date);
-          taxis->stime = cdiTime_get(sDateTime.time);
+          taxis->sDateTime = sDateTime;
         }
       else
         {
-          if (cdiDateTime_isLT(sDateTime, cdiDateTime_set(taxis->sdate, taxis->stime)))
-            {
-              taxis->sdate = cdiDate_get(sDateTime.date);
-              taxis->stime = cdiTime_get(sDateTime.time);
-            }
+          if (cdiDateTime_isLT(sDateTime, taxis->sDateTime)) taxis->sDateTime = sDateTime;
         }
 
       const int tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
@@ -1213,16 +1203,11 @@ cgribexScanTimestep(stream_t *streamptr)
                 }
               taxis->unit = cgribexGetTimeUnit(isec1);
               taxis->vdatetime = vDateTime;
-              taxis->sdate = cdiDate_get(sDateTime.date);
-              taxis->stime = cdiTime_get(sDateTime.time);
+              taxis->sDateTime = sDateTime;
             }
           else
             {
-              if (cdiDateTime_isLT(sDateTime, cdiDateTime_set(taxis->sdate, taxis->stime)))
-                {
-                  taxis->sdate = cdiDate_get(sDateTime.date);
-                  taxis->stime = cdiTime_get(sDateTime.time);
-                }
+              if (cdiDateTime_isLT(sDateTime, taxis->sDateTime)) taxis->sDateTime = sDateTime;
             }
 
           if (ISEC1_AvgNum)
@@ -1451,16 +1436,12 @@ cgribexDefParam(int *isec1, int param)
 }
 
 static int
-cgribexDefTimerange(int tsteptype, int factor, int calendar, int rdate, int rtime, int vdate, int vtime, int sdate, int stime,
+cgribexDefTimerange(int tsteptype, int factor, int calendar, CdiDateTime rDateTime, CdiDateTime vDateTime, CdiDateTime sDateTime,
                     int *pip1, int *pip2)
 {
-  CdiDateTime rDateTime = cdiDateTime_set(rdate, rtime);
   JulianDate julianDate1 = julianDate_encode(calendar, rDateTime);
-
-  CdiDateTime vDateTime = cdiDateTime_set(vdate, vtime);
   JulianDate julianDate2 = julianDate_encode(calendar, vDateTime);
-
-  JulianDate julianDate = julianDate_sub(julianDate2, julianDate1);
+  const JulianDate julianDate = julianDate_sub(julianDate2, julianDate1);
 
   int timerange = -1;
   int ip1 = 0, ip2 = 0;
@@ -1470,14 +1451,11 @@ cgribexDefTimerange(int tsteptype, int factor, int calendar, int rdate, int rtim
       if ((ip > 255) && (tsteptype == TSTEP_INSTANT)) tsteptype = TSTEP_INSTANT3;
 
       int ipx = 0;
-      if (sdate != 0 && (tsteptype == TSTEP_RANGE || tsteptype == TSTEP_AVG || tsteptype == TSTEP_ACCUM || tsteptype == TSTEP_DIFF))
+      if (!cdiDateTime_isNull(sDateTime) &&
+          (tsteptype == TSTEP_RANGE || tsteptype == TSTEP_AVG || tsteptype == TSTEP_ACCUM || tsteptype == TSTEP_DIFF))
         {
-          CdiDateTime sDateTime = cdiDateTime_set(sdate, stime);
           julianDate2 = julianDate_encode(calendar, sDateTime);
-
-          julianDate = julianDate_sub(julianDate2, julianDate1);
-
-          ipx = (int) lround(julianDate_to_seconds(julianDate) / factor);
+          ipx = (int) lround(julianDate_to_seconds(julianDate_sub(julianDate2, julianDate1)) / factor);
         }
 
       // clang-format off
@@ -1502,11 +1480,11 @@ cgribexDefTimerange(int tsteptype, int factor, int calendar, int rdate, int rtim
 }
 
 static int
-cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
+cgribexDefDateTime(int *isec1, int timeunit, CdiDateTime dt)
 {
-  int year, month, day, hour, minute, second;
-  cdiDecodeDate(date, &year, &month, &day);
-  cdiDecodeTime(time, &hour, &minute, &second);
+  int year, month, day, hour, minute, second, ms;
+  cdiDate_decode(dt.date, &year, &month, &day);
+  cdiTime_decode(dt.time, &hour, &minute, &second, &ms);
 
   int century = year / 100;
 
@@ -1554,7 +1532,7 @@ cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
 }
 
 static void
-cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg, int taxisID)
+cgribexDefTime(int *isec1, CdiDateTime vDateTime, int tsteptype, int numavg, int taxisID)
 {
   int timetype = TAXIS_ABSOLUTE;
   int timeunit = TUNIT_HOUR;
@@ -1569,26 +1547,20 @@ cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg, int
     {
       const int calendar = taxisInqCalendar(taxisID);
 
-      int rdate = taxisInqRdate(taxisID);
-      int rtime = taxisInqRtime(taxisID);
-      if (vdate < rdate || (vdate == rdate && vtime < rtime))
-        {
-          rdate = vdate;
-          rtime = vtime;
-        }
+      CdiDateTime rDateTime = taxisInqRdatetime(taxisID);
+      if (cdiDateTime_isLT(vDateTime, rDateTime)) rDateTime = vDateTime;
 
-      int sdate = taxisInqSdate(taxisID);
-      int stime = taxisInqStime(taxisID);
+      CdiDateTime sDateTime = taxisInqSdatetime(taxisID);
 
-      int factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
+      int factor = cgribexDefDateTime(isec1, timeunit, rDateTime);
       int ip1 = 0, ip2 = 0;
-      int timerange = cgribexDefTimerange(tsteptype, factor, calendar, rdate, rtime, vdate, vtime, sdate, stime, &ip1, &ip2);
+      int timerange = cgribexDefTimerange(tsteptype, factor, calendar, rDateTime, vDateTime, sDateTime, &ip1, &ip2);
 
       if (ip2 > 0xFF && timeunit < TUNIT_YEAR)
         {
           timeunit++;
-          factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
-          timerange = cgribexDefTimerange(tsteptype, factor, calendar, rdate, rtime, vdate, vtime, sdate, stime, &ip1, &ip2);
+          factor = cgribexDefDateTime(isec1, timeunit, rDateTime);
+          timerange = cgribexDefTimerange(tsteptype, factor, calendar, rDateTime, vDateTime, sDateTime, &ip1, &ip2);
         }
 
       if (timerange == -1 || timerange == 1 || timerange == 3) timetype = TAXIS_ABSOLUTE;
@@ -1619,7 +1591,7 @@ cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg, int
 
   if (timetype == TAXIS_ABSOLUTE)
     {
-      (void) cgribexDefDateTime(isec1, timeunit, vdate, vtime);
+      (void) cgribexDefDateTime(isec1, timeunit, vDateTime);
 
       /*
       if ( numavg > 0 )
@@ -2067,7 +2039,7 @@ cgribexDefEnsembleVar(int *isec1, int vlistID, int varID)
 }
 
 size_t
-cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID, int vdate, int vtime, int tsteptype,
+cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID, CdiDateTime vDateTime, int tsteptype,
               int numavg, size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize)
 {
   cgribexrec_t *cgribexp = (cgribexrec_t *) cgribexNew();
@@ -2111,7 +2083,7 @@ cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int
   cdiInqKeyInt(vlistID, varID, CDI_KEY_UVRELATIVETOGRID, &uvRelativeToGrid);
 
   cgribexDefParam(isec1, param);
-  cgribexDefTime(isec1, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID));
+  cgribexDefTime(isec1, vDateTime, tsteptype, numavg, vlistInqTaxis(vlistID));
   cgribexDefGrid(isec1, isec2, fsec2, isec4, gridID, uvRelativeToGrid);
   cgribexDefLevel(isec1, isec2, fsec2, zaxisID, levelID);
 
diff --git a/src/stream_cgribex.h b/src/stream_cgribex.h
index 96e9f5db39f570891ad7f49bcbf10bd3fd785f3c..2bca10dfee763224938a15cda4e1cbf83e555015 100644
--- a/src/stream_cgribex.h
+++ b/src/stream_cgribex.h
@@ -11,7 +11,7 @@ int cgribexScanTimestep(stream_t *streamptr);
 int cgribexDecode(int memtype, void *cgribexp, void *gribbuffer, size_t gribsize, void *data, size_t datasize, int unreduced,
                   size_t *nmiss, double missval);
 
-size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID, int vdate, int vtime, int tsteptype,
+size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID, CdiDateTime vDateTime, int tsteptype,
                      int numavg, size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize);
 
 void *cgribex_handle_new_from_meassage(void *gribbuffer, size_t recsize);
diff --git a/src/stream_gribapi.c b/src/stream_gribapi.c
index dd5e49b2807137feabad049136ccd093b302acad..ce5e3c5821f0ab555412773776db56892ef90f6c 100644
--- a/src/stream_gribapi.c
+++ b/src/stream_gribapi.c
@@ -138,11 +138,13 @@ gribapiGetDataDateTime(grib_handle *gh)
 }
 
 static void
-gribapiSetDataDateTime(grib_handle *gh, int datadate, int datatime)
+gribapiSetDataDateTime(grib_handle *gh, CdiDateTime dataDateTime)
 {
-  GRIB_CHECK(my_grib_set_long(gh, "dataDate", (long) datadate), 0);
-  int hour, minute, second;
-  cdiDecodeTime(datatime, &hour, &minute, &second);
+  long dataDate = (long)cdiDate_get(dataDateTime.date);
+  GRIB_CHECK(my_grib_set_long(gh, "dataDate", (long) dataDate), 0);
+
+  int hour, minute, second, ms;
+  cdiTime_decode(dataDateTime.time, &hour, &minute, &second, &ms);
   GRIB_CHECK(my_grib_set_long(gh, "hour", hour), 0);
   GRIB_CHECK(my_grib_set_long(gh, "minute", minute), 0);
   GRIB_CHECK(my_grib_set_long(gh, "second", second), 0);
@@ -1073,10 +1075,8 @@ fdbScanTimesteps(stream_t *streamptr)
           taxis->rdatetime = gribapiGetDataDateTime(gh);
           fcast = gribapiTimeIsFC(gh);
           if (fcast) taxis->unit = gribapiGetTimeUnits(gh);
-          taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
-          taxis->ftime = cdiTime_get(taxis->rdatetime.time);
-          taxis->sdate = cdiDate_get(sDateTime.date);
-          taxis->stime = cdiTime_get(sDateTime.time);
+          taxis->fDateTime = taxis->rdatetime;
+          taxis->sDateTime = sDateTime;
           taxis->vdatetime = vDateTime;
         }
 
@@ -1238,19 +1238,13 @@ gribapiScanTimestep1(stream_t *streamptr)
           taxis->rdatetime = gribapiGetDataDateTime(gh);
           fcast = gribapiTimeIsFC(gh);
           if (fcast) taxis->unit = gribapiGetTimeUnits(gh);
-          taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
-          taxis->ftime = cdiTime_get(taxis->rdatetime.time);
-          taxis->sdate = cdiDate_get(sDateTime.date);
-          taxis->stime = cdiTime_get(sDateTime.time);
+          taxis->fDateTime = taxis->rdatetime;
+          taxis->sDateTime = sDateTime;
           taxis->vdatetime = vDateTime;
         }
       else
         {
-          if (cdiDateTime_isLT(sDateTime, cdiDateTime_set(taxis->sdate, taxis->stime)))
-            {
-              taxis->sdate = cdiDate_get(sDateTime.date);
-              taxis->stime = cdiTime_get(sDateTime.time);
-            }
+          if (cdiDateTime_isLT(sDateTime, taxis->sDateTime)) taxis->sDateTime = sDateTime;
 
           const int tsteptype = gribapiGetTsteptype(gh);
           const size_t gridsize = gribapiGetGridsize(gh);
@@ -1311,7 +1305,6 @@ gribapiScanTimestep1(stream_t *streamptr)
 
   taxis->type = fcast ? TAXIS_RELATIVE : TAXIS_ABSOLUTE;
   const int taxisID = taxisCreate(taxis->type);
-  // printf("1: %d %6d  %d %6d  %d %6d\n", taxis->rdate, taxis->rtime, taxis->sdate, taxis->stime, taxis->vdate, taxis->vtime);
 
   const int vlistID = streamptr->vlistID;
   vlistDefTaxis(vlistID, taxisID);
@@ -1411,21 +1404,13 @@ gribapiScanTimestep2(stream_t *streamptr)
             {
               taxis->type = TAXIS_ABSOLUTE;
             }
-          taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
-          taxis->ftime = cdiTime_get(taxis->rdatetime.time);
+          taxis->fDateTime = taxis->rdatetime;
           taxis->vdatetime = vDateTime;
-          taxis->sdate = cdiDate_get(sDateTime.date);
-          taxis->stime = cdiTime_get(sDateTime.time);
-          // printf("2: %d %6d  %d %6d  %d %6d\n", taxis->rdate, taxis->rtime, taxis->sdate, taxis->stime, taxis->vdate,
-          // taxis->vtime);
+          taxis->sDateTime = sDateTime;
         }
       else
         {
-          if (cdiDateTime_isLT(sDateTime, cdiDateTime_set(taxis->sdate, taxis->stime)))
-            {
-              taxis->sdate = cdiDate_get(sDateTime.date);
-              taxis->stime = cdiTime_get(sDateTime.time);
-            }
+          if (cdiDateTime_isLT(sDateTime, taxis->sDateTime)) taxis->sDateTime = sDateTime;
         }
 
       VarScanKeys scanKeys = gribapiGetScanKeys(gh);
@@ -1604,21 +1589,13 @@ gribapiScanTimestep(stream_t *streamptr)
                 {
                   taxis->type = TAXIS_ABSOLUTE;
                 }
-              taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
-              taxis->ftime = cdiTime_get(taxis->rdatetime.time);
+              taxis->fDateTime = taxis->rdatetime;
               taxis->vdatetime = vDateTime;
-              taxis->sdate = cdiDate_get(sDateTime.date);
-              taxis->stime = cdiTime_get(sDateTime.time);
-              // printf("n: %d %6d  %d %6d  %d %6d\n", taxis->rdate, taxis->rtime, taxis->sdate, taxis->stime, taxis->vdate,
-              // taxis->vtime);
+              taxis->sDateTime = sDateTime;
             }
           else
             {
-              if (cdiDateTime_isLT(sDateTime, cdiDateTime_set(taxis->sdate, taxis->stime)))
-                {
-                  taxis->sdate = cdiDate_get(sDateTime.date);
-                  taxis->stime = cdiTime_get(sDateTime.time);
-                }
+              if (cdiDateTime_isLT(sDateTime, taxis->sDateTime)) taxis->sDateTime = sDateTime;
             }
 
           VarScanKeys scanKeys = gribapiGetScanKeys(gh);
@@ -2004,7 +1981,7 @@ gribapiDefSteptype(int editionNumber, grib_handle *gh, int productDefinitionTemp
 }
 
 static void
-gribapiDefDateTimeAbs(int editionNumber, grib_handle *gh, int date, int time, int productDefinitionTemplate,
+gribapiDefDateTimeAbs(int editionNumber, grib_handle *gh, CdiDateTime dateTime, int productDefinitionTemplate,
                       int typeOfGeneratingProcess, int tsteptype, int gcinit)
 {
   (void) gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
@@ -2012,30 +1989,23 @@ gribapiDefDateTimeAbs(int editionNumber, grib_handle *gh, int date, int time, in
   if (editionNumber > 1) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 0), 0);
   if (editionNumber > 1) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
 
-  if (date == 0) date = 10101;
-  gribapiSetDataDateTime(gh, date, time);
+  if (cdiDateTime_isNull(dateTime)) dateTime.date = cdiDate_set(10101);
+  gribapiSetDataDateTime(gh, dateTime);
 }
 
 static int
-gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int fdate, int ftime, int vdate, int vtime, int sdate, int stime,
+gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, CdiDateTime fDateTime, CdiDateTime vDateTime, CdiDateTime sDateTime,
                       int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int timeunit, int calendar,
                       int gcinit)
 {
   int status = -1;
 
-  CdiDateTime fDateTime = cdiDateTime_set(fdate, ftime);
   JulianDate julianDate1 = julianDate_encode(calendar, fDateTime);
 
-  if (vdate == 0 && vtime == 0)
-    {
-      vdate = fdate;
-      vtime = ftime;
-    }
+  if (cdiDateTime_isNull(vDateTime)) vDateTime = fDateTime;
 
-  CdiDateTime vDateTime = cdiDateTime_set(vdate, vtime);
   JulianDate julianDate2 = julianDate_encode(calendar, vDateTime);
-
-  JulianDate julianDate = julianDate_sub(julianDate2, julianDate1);
+  const JulianDate julianDate = julianDate_sub(julianDate2, julianDate1);
 
   const int factor = getTimeunitFactor(timeunit);
 
@@ -2054,21 +2024,17 @@ gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int fdate, int ftime,
       bool hasStartDate = (tsteptype == TSTEP_RANGE || tsteptype == TSTEP_AVG || tsteptype == TSTEP_ACCUM || tsteptype == TSTEP_DIFF
                            || tsteptype == TSTEP_MIN || tsteptype == TSTEP_MAX || tsteptype == TSTEP_RMS || tsteptype == TSTEP_SD
                            || tsteptype == TSTEP_COV || tsteptype == TSTEP_RATIO || tsteptype == TSTEP_SUM);
-      if (sdate != 0 && hasStartDate)
+      if (!cdiDateTime_isNull(sDateTime) && hasStartDate)
         {
-          CdiDateTime sDateTime = cdiDateTime_set(sdate, stime);
           julianDate2 = julianDate_encode(calendar, sDateTime);
-
-          julianDate = julianDate_sub(julianDate2, julianDate1);
-
-          startStep = lround(julianDate_to_seconds(julianDate) / factor);
+          startStep = lround(julianDate_to_seconds(julianDate_sub(julianDate2, julianDate1)) / factor);
         }
 
       if (editionNumber > 1) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 1), 0);
       if (editionNumber > 1) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
 
-      if (fdate == 0) fdate = 10101;
-      gribapiSetDataDateTime(gh, fdate, ftime);
+      if (cdiDateTime_isNull(fDateTime)) fDateTime.date = cdiDate_set(10101);
+      gribapiSetDataDateTime(gh, fDateTime);
 
       // printf(">>>>> tsteptype %d  startStep %ld  endStep %ld\n", tsteptype, startStep, endStep);
 
@@ -2098,7 +2064,7 @@ gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int fdate, int ftime,
 }
 
 static void
-gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGeneratingProcess, grib_handle *gh, int vdate, int vtime,
+gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGeneratingProcess, grib_handle *gh, CdiDateTime vDateTime,
                int tsteptype, int numavg, int taxisID, int gcinit)
 {
   UNUSED(numavg);
@@ -2107,8 +2073,7 @@ gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGener
 
   if (typeOfGeneratingProcess == 196)
     {
-      vdate = 10101;
-      vtime = 0;
+      vDateTime = cdiDateTime_set(10101, 0);
       taxistype = TAXIS_ABSOLUTE;
     }
 
@@ -2117,29 +2082,19 @@ gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGener
       const int timeunit = taxisInqTunit(taxisID);
       const int calendar = taxisInqCalendar(taxisID);
 
-      int fdate = taxisInqFdate(taxisID);
-      int ftime = taxisInqFtime(taxisID);
-      if (fdate == CDI_UNDEFID)
-        {
-          fdate = taxisInqRdate(taxisID);
-          ftime = taxisInqRtime(taxisID);
-        }
-      if (vdate < fdate || (vdate == fdate && vtime < ftime))
-        {
-          fdate = vdate;
-          ftime = vtime;
-        }
+      CdiDateTime fDateTime = taxisInqFdatetime(taxisID);
+      if (cdiDateTime_isNull(fDateTime)) fDateTime = taxisInqRdatetime(taxisID);
+      if (cdiDateTime_isLT(vDateTime, fDateTime)) fDateTime = vDateTime;
 
-      const int sdate = taxisInqSdate(taxisID);
-      const int stime = taxisInqStime(taxisID);
+      const CdiDateTime sDateTime = taxisInqSdatetime(taxisID);
 
-      int status = gribapiDefDateTimeRel(editionNumber, gh, fdate, ftime, vdate, vtime, sdate, stime, productDefinitionTemplate,
+      int status = gribapiDefDateTimeRel(editionNumber, gh, fDateTime, vDateTime, sDateTime, productDefinitionTemplate,
                                          typeOfGeneratingProcess, tsteptype, timeunit, calendar, gcinit);
       if (status != 0) taxistype = TAXIS_ABSOLUTE;
     }
 
   if (taxistype == TAXIS_ABSOLUTE)
-    gribapiDefDateTimeAbs(editionNumber, gh, vdate, vtime, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
+    gribapiDefDateTimeAbs(editionNumber, gh, vDateTime, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
 }
 
 static void
@@ -3228,7 +3183,7 @@ gribapiSetExtMode(grib_handle *gh, int gridID, size_t datasize, const void *data
 // #define GRIBAPIENCODETEST 1
 
 size_t
-gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID, int vdate, int vtime, int tsteptype, int numavg,
+gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID, CdiDateTime vDateTime, int tsteptype, int numavg,
               size_t datasize, const void *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize, int comptype,
               void *gribContainer)
 {
@@ -3286,7 +3241,7 @@ gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID, int
         }
     }
 
-  gribapiDefTime((int) editionNumber, productDefinitionTemplate, typeOfGeneratingProcess, gh, vdate, vtime, tsteptype, numavg,
+  gribapiDefTime((int) editionNumber, productDefinitionTemplate, typeOfGeneratingProcess, gh, vDateTime, tsteptype, numavg,
                  vlistInqTaxis(vlistID), gc->init);
 
   {
diff --git a/src/stream_gribapi.h b/src/stream_gribapi.h
index cd7f6f71b71820895fd5e2e68852dd41333212c9..b5e6def463a96112fdb0cfe6be9f7b0594474f8e 100644
--- a/src/stream_gribapi.h
+++ b/src/stream_gribapi.h
@@ -13,7 +13,7 @@ int gribapiScanTimestep(stream_t *streamptr);
 
 int gribapiDecode(void *gribbuffer, size_t gribsize, void *data, size_t datasize, int unreduced, size_t *nmiss, double missval);
 
-size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID, int vdate, int vtime, int tsteptype, int numavg,
+size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID, CdiDateTime vDateTime, int tsteptype, int numavg,
                      size_t datasize, const void *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize, int ljpeg,
                      void *gribContainer);
 
diff --git a/src/taxis.c b/src/taxis.c
index 811e48b367a8ab2252bb76c4e653be20f5d3d070..a3c1bc9b77c9d599e7e043550e5365f340d04aa7 100644
--- a/src/taxis.c
+++ b/src/taxis.c
@@ -89,17 +89,15 @@ taxisDefaultValue(taxis_t *taxisptr)
   taxisptr->used = false;
   taxisptr->datatype = CDI_DATATYPE_FLT64;
   taxisptr->type = DefaultTimeType;
-  taxisptr->sdate = 0;
-  taxisptr->stime = 0;
-  cdiDateTime_init(&taxisptr->vdatetime);
-  cdiDateTime_init(&taxisptr->rdatetime);
-  taxisptr->fdate = CDI_UNDEFID;
-  taxisptr->ftime = 0;
   taxisptr->calendar = CDI_Default_Calendar;
   taxisptr->unit = DefaultTimeUnit;
   taxisptr->numavg = 0;
   taxisptr->climatology = false;
   taxisptr->has_bounds = false;
+  cdiDateTime_init(&taxisptr->sDateTime);
+  cdiDateTime_init(&taxisptr->vdatetime);
+  cdiDateTime_init(&taxisptr->rdatetime);
+  cdiDateTime_init(&taxisptr->fDateTime);
   cdiDateTime_init(&taxisptr->vdatetime_lb);
   cdiDateTime_init(&taxisptr->vdatetime_ub);
   taxisptr->fc_unit = DefaultTimeUnit;
@@ -418,9 +416,9 @@ taxisDefFdate(int taxisID, int fdate)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->fdate != fdate)
+  if (cdiDate_get(taxisptr->fDateTime.date) != fdate)
     {
-      taxisptr->fdate = fdate;
+      taxisptr->fDateTime.date = cdiDate_set(fdate);
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -444,9 +442,9 @@ taxisDefFtime(int taxisID, int ftime)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->ftime != ftime)
+  if (cdiTime_get(taxisptr->fDateTime.time) != ftime)
     {
-      taxisptr->ftime = ftime;
+      taxisptr->fDateTime.time = cdiTime_set(ftime);
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -583,10 +581,9 @@ taxisCopyTimestep(int taxisID2, int taxisID1)
 
   // reference date/time and units can't be changed after streamDefVlist()!
 
-  taxisptr2->sdate = taxisptr1->sdate;
-  taxisptr2->stime = taxisptr1->stime;
-
+  taxisptr2->sDateTime = taxisptr1->sDateTime;
   taxisptr2->vdatetime = taxisptr1->vdatetime;
+  taxisptr2->fDateTime = taxisptr1->fDateTime;
 
   if (taxisptr2->has_bounds)
     {
@@ -594,9 +591,6 @@ taxisCopyTimestep(int taxisID2, int taxisID1)
       taxisptr2->vdatetime_ub = taxisptr1->vdatetime_ub;
     }
 
-  taxisptr2->fdate = taxisptr1->fdate;
-  taxisptr2->ftime = taxisptr1->ftime;
-
   taxisptr2->fc_unit = taxisptr1->fc_unit;
   taxisptr2->fc_period = taxisptr1->fc_period;
 
@@ -625,6 +619,20 @@ taxisInqRdatetime(int taxisID)
   return taxisptr->rdatetime;
 }
 
+CdiDateTime
+taxisInqFdatetime(int taxisID)
+{
+  taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
+
+  if (cdiDateTime_isNull(taxisptr->fDateTime))
+    {
+      taxisptr->fDateTime = taxisInqRdatetime(taxisID);
+      reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
+    }
+
+  return taxisptr->rdatetime;
+}
+
 /*
 @Function  taxisInqVdate
 @Title     Get the verification date
@@ -648,11 +656,11 @@ taxisInqVdate(int taxisID)
   return (int) cdiDate_get(taxisptr->vdatetime.date);
 }
 
-int
-taxisInqSdate(int taxisID)
+CdiDateTime
+taxisInqSdatetime(int taxisID)
 {
   const taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
-  return taxisptr->sdate;
+  return taxisptr->sDateTime;
 }
 
 void
@@ -721,17 +729,9 @@ int
 taxisInqVtime(int taxisID)
 {
   const taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
-  // return taxisptr->vtime;
   return cdiTime_get(taxisptr->vdatetime.time);
 }
 
-int
-taxisInqStime(int taxisID)
-{
-  const taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
-  return taxisptr->stime;
-}
-
 void
 taxisInqVtimeBounds(int taxisID, int *vtime_lb, int *vtime_ub)
 {
@@ -836,14 +836,13 @@ taxisInqFdate(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->fdate == -1)
+  if (cdiDateTime_isNull(taxisptr->fDateTime))
     {
       // rdatetime is initialized from vdatetime if empty!
-      taxisptr->fdate = taxisInqRdate(taxisID);
-      taxisptr->ftime = taxisInqRtime(taxisID);
+      taxisptr->fDateTime = taxisInqRdatetime(taxisID);
     }
 
-  return taxisptr->fdate;
+  return cdiDate_get(taxisptr->fDateTime.date);
 }
 
 /*
@@ -867,14 +866,13 @@ taxisInqFtime(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->fdate == -1)
+  if (cdiDateTime_isNull(taxisptr->fDateTime))
     {
       // rdatetime is initialized from vdatetime if empty!
-      taxisptr->fdate = taxisInqRdate(taxisID);
-      taxisptr->ftime = taxisInqRtime(taxisID);
+      taxisptr->fDateTime = taxisInqRdatetime(taxisID);
     }
 
-  return taxisptr->ftime;
+  return cdiTime_get(taxisptr->fDateTime.time);
 }
 
 /*
@@ -1357,10 +1355,7 @@ cdiSetForecastPeriod(double timevalue, taxis_t *taxis)
   const JulianDate julianDate = julianDate_encode(calendar, vdatetime);
   const JulianDate julianDate2 = timevalue_decode(timeunits, timevalue);
 
-  const CdiDateTime dt = julianDate_decode(calendar, julianDate_sub(julianDate, julianDate2));
-
-  (*taxis).fdate = (int) cdiDate_get(dt.date);
-  (*taxis).ftime = (int) cdiTime_get(dt.time);
+  (*taxis).fDateTime = julianDate_decode(calendar, julianDate_sub(julianDate, julianDate2));
 }
 
 CdiDateTime
@@ -1420,17 +1415,15 @@ ptaxisCopy(taxis_t *dest, taxis_t *source)
   dest->used = source->used;
   dest->datatype = source->datatype;
   dest->type = source->type;
-  dest->sdate = source->sdate;
-  dest->stime = source->stime;
-  dest->vdatetime = source->vdatetime;
-  dest->rdatetime = source->rdatetime;
-  dest->fdate = source->fdate;
-  dest->ftime = source->ftime;
   dest->calendar = source->calendar;
   dest->unit = source->unit;
   dest->numavg = source->numavg;
   dest->climatology = source->climatology;
   dest->has_bounds = source->has_bounds;
+  dest->sDateTime = source->sDateTime;
+  dest->vdatetime = source->vdatetime;
+  dest->rdatetime = source->rdatetime;
+  dest->fDateTime = source->fDateTime;
   dest->vdatetime_lb = source->vdatetime_lb;
   dest->vdatetime_ub = source->vdatetime_ub;
   dest->fc_unit = source->fc_unit;
@@ -1484,7 +1477,8 @@ taxisPrintKernel(taxis_t *taxisptr, FILE *fp)
           "\n",
           taxisptr->self, taxisptr->self, (int) taxisptr->used, taxisptr->type, (int) cdiDate_get(taxisptr->vdatetime.date),
           cdiTime_get(taxisptr->vdatetime.time), (int) cdiDate_get(taxisptr->rdatetime.date), cdiTime_get(taxisptr->rdatetime.time),
-          taxisptr->fdate, taxisptr->ftime, taxisptr->calendar, taxisptr->unit, taxisptr->numavg, (int) taxisptr->climatology,
+          (int) cdiDate_get(taxisptr->fDateTime.date), cdiTime_get(taxisptr->fDateTime.time), taxisptr->calendar,
+          taxisptr->unit, taxisptr->numavg, (int) taxisptr->climatology,
           (int) taxisptr->has_bounds, vdate_lb, vtime_lb, vdate_ub, vtime_ub, taxisptr->fc_unit, taxisptr->fc_period);
 }
 
@@ -1496,7 +1490,7 @@ taxisCompareP(void *taxisptr1, void *taxisptr2)
   xassert(t1 && t2);
 
   return !(t1->used == t2->used && t1->type == t2->type && cdiDateTime_isEQ(t1->vdatetime, t2->vdatetime)
-           && cdiDateTime_isEQ(t1->rdatetime, t2->rdatetime) && t1->fdate == t2->fdate && t1->ftime == t2->ftime
+           && cdiDateTime_isEQ(t1->rdatetime, t2->rdatetime) && cdiDateTime_isEQ(t1->fDateTime, t2->fDateTime)
            && t1->calendar == t2->calendar && t1->unit == t2->unit && t1->fc_unit == t2->fc_unit && t1->numavg == t2->numavg
            && t1->climatology == t2->climatology && t1->has_bounds == t2->has_bounds
            && cdiDateTime_isEQ(t1->vdatetime_lb, t2->vdatetime_lb) && cdiDateTime_isEQ(t1->vdatetime_ub, t2->vdatetime_ub));
@@ -1550,8 +1544,8 @@ taxisUnpack(char *unpackBuffer, int unpackBufferSize, int *unpackBufferPos, int
   taxisP->vdatetime.time = cdiTime_set(intBuffer[idx++]);
   taxisP->rdatetime.date = cdiDate_set(intBuffer[idx++]);
   taxisP->rdatetime.time = cdiTime_set(intBuffer[idx++]);
-  taxisP->fdate = intBuffer[idx++];
-  taxisP->ftime = intBuffer[idx++];
+  taxisP->fDateTime.date = cdiDate_set(intBuffer[idx++]);
+  taxisP->fDateTime.time = cdiTime_set(intBuffer[idx++]);
   taxisP->calendar = intBuffer[idx++];
   taxisP->unit = intBuffer[idx++];
   taxisP->fc_unit = intBuffer[idx++];
@@ -1608,8 +1602,8 @@ taxisPack(void *voidP, void *packBuffer, int packBufferSize, int *packBufferPos,
   intBuffer[idx++] = cdiTime_get(taxisP->vdatetime.time);
   intBuffer[idx++] = (int) cdiDate_get(taxisP->rdatetime.date);
   intBuffer[idx++] = cdiTime_get(taxisP->rdatetime.time);
-  intBuffer[idx++] = taxisP->fdate;
-  intBuffer[idx++] = taxisP->ftime;
+  intBuffer[idx++] = (int) cdiDate_get(taxisP->fDateTime.date);
+  intBuffer[idx++] = cdiTime_get(taxisP->fDateTime.time);
   intBuffer[idx++] = taxisP->calendar;
   intBuffer[idx++] = taxisP->unit;
   intBuffer[idx++] = taxisP->fc_unit;
diff --git a/src/taxis.h b/src/taxis.h
index c9f3526bf9f4aa9f96cfc596ae99363be5ba9dec..38b11c8c952b432e6d36ceafc602e834f355da33 100644
--- a/src/taxis.h
+++ b/src/taxis.h
@@ -10,23 +10,19 @@
 
 typedef struct
 {
-  // Date format  YYYYMMDD
-  // Time format    hhmmss
   int self;
   bool used;
   short has_bounds;
-  int datatype;           // datatype
-  int type;               // time type
-  int sdate;              // start date
-  int stime;              // start time
-  CdiDateTime vdatetime;  // verification date/time
-  CdiDateTime rdatetime;  // reference date/time
-  int fdate;              // forecast reference date
-  int ftime;              // forecast reference time
+  int datatype;              // datatype
+  int type;                  // time type
   int calendar;
   int unit;  // time unit
   int numavg;
   bool climatology;
+  CdiDateTime sDateTime;     // start date/time
+  CdiDateTime vdatetime;     // verification date/time
+  CdiDateTime rdatetime;     // reference date/time
+  CdiDateTime fDateTime;     // forecast reference date/time
   CdiDateTime vdatetime_lb;  // lower bounds of verification date/time
   CdiDateTime vdatetime_ub;  // upper bounds of verification date/time
   int fc_unit;               // forecast time unit
@@ -36,11 +32,8 @@ typedef struct
   char *units;
 } taxis_t;
 
-//      taxisInqSdate: Get the start date
-int taxisInqSdate(int taxisID);
-
-//      taxisInqStime: Get the start time
-int taxisInqStime(int taxisID);
+//      taxisInqSdatetime: Get the start date/time
+CdiDateTime taxisInqSdatetime(int taxisID);
 
 void ptaxisInit(taxis_t *taxis);
 void ptaxisCopy(taxis_t *dest, taxis_t *source);