diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 089e9fbb12..c02e20b678 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -27,6 +27,7 @@ d866510188d26d51bcd6d37239283db690af7e82
 e096358c832ab292ddfd22dd5878826c7c788968
 475831f0fb0e31e97f630eac4e078c886558b61c
 fd5f177131d63d39e79a13918390bdfb642d781e
+a51816e0de380300b69db9fc3e2c7fa83b267b64
 # Ran SystemTests and python/ctsm through black python formatter
 5364ad66eaceb55dde2d3d598fe4ce37ac83a93c
 8056ae649c1b37f5e10aaaac79005d6e3a8b2380
diff --git a/.gitmodules b/.gitmodules
index a7acd7fd08..bc66fe1682 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -44,7 +44,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/CISM-wrapper
 [submodule "rtm"]
 path = components/rtm
 url = https://github.com/ESCOMP/RTM
-fxtag = rtm1_0_80
+fxtag = rtm1_0_84
 fxrequired = ToplevelRequired
 # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
 fxDONOTUSEurl = https://github.com/ESCOMP/RTM
@@ -52,7 +52,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/RTM
 [submodule "mosart"]
 path = components/mosart
 url = https://github.com/ESCOMP/MOSART
-fxtag = mosart1.1.02
+fxtag = mosart1.1.06
 fxrequired = ToplevelRequired
 # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed
 fxDONOTUSEurl = https://github.com/ESCOMP/MOSART
diff --git a/components/mosart b/components/mosart
index e2ffe00004..a246344e9b 160000
--- a/components/mosart
+++ b/components/mosart
@@ -1 +1 @@
-Subproject commit e2ffe00004cc416cfc8bcfae2a949474075c1d1f
+Subproject commit a246344e9b28e4bb42313749094fa20d45e2b212
diff --git a/components/rtm b/components/rtm
index b3dfcfbba5..6899b55816 160000
--- a/components/rtm
+++ b/components/rtm
@@ -1 +1 @@
-Subproject commit b3dfcfbba58c151ac5a6ab513b3515ef3deff798
+Subproject commit 6899b55816ee4d9b7cf983d74ba2997b97a13c4d
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 1b37b4be63..5357d81b5f 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,4 +1,112 @@
 ===============================================================
+Tag name: ctsm5.3.018
+Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310)
+Date: Fri 10 Jan 2025 05:37:08 PM MST
+One-line Summary: Change history time to be the middle of the time bounds
+
+Purpose and description of changes
+----------------------------------
+ Making the change to be consistent with CAM and to make history output more intuitive.
+
+Significant changes to scientifically-supported configurations
+--------------------------------------------------------------
+
+Does this tag change answers significantly for any of the following physics configurations?
+(Details of any changes will be given in the "Answer changes" section below.)
+
+    [Put an [X] in the box for any configuration with significant answer changes.]
+
+[ ] clm6_0
+
+[ ] clm5_1
+
+[ ] clm5_0
+
+[ ] ctsm5_0-nwp
+
+[ ] clm4_5
+
+
+Bugs fixed
+----------
+List of CTSM issues fixed (include CTSM Issue # and description) [one per line]:
+ Partly addresses issue #1059
+
+Notes of particular relevance for users
+---------------------------------------
+Caveats for users (e.g., need to interpolate initial conditions):
+ The history time variable now equals the middle of the time bounds.
+ Instantaneous history tapes now do not include time bounds.
+ Mixed history tapes do not change the treatment of instantaneous fields or move them to separate tapes, yet.
+
+Notes of particular relevance for developers:
+---------------------------------------------
+Caveats for developers (e.g., code that is duplicated that requires double maintenance):
+ Same changes are needed separately in clm, in mosart, and in rtm.
+
+Changes to tests or testing:
+ This tag introduces changes to the mosart/rtm testlists.
+
+ FAIL RXCROPMATURITYSKIPGEN_Ld1097.f10_f10_mg37.IHistClm60BgcCrop.derecho_intel.clm-cropMonthOutput RUN
+ I did not label this failure EXPECTED because the fix comes in later in this series of "history" tags, in particular ctsm5.3.020.
+
+ I resolved the izumi nag tests that failed to build (due to a bug in rtm and mosart) by introducing the bug-fix manually, as explained here:
+https://github.com/ESCOMP/CTSM/pull/2084#issuecomment-2584164690
+ In the next tag we expect to update to the rtm/mosart tags that include the fix.
+
+Testing summary:
+----------------
+
+ [PASS means all tests PASS; OK means tests PASS other than expected fails.]
+
+  build-namelist tests
+
+    derecho - PASS
+
+  python testing (if python code has changed; see instructions in python/README.md; document testing done):
+
+    derecho - PASS
+
+  regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing):
+
+    derecho ----- OK
+    izumi ------- OK
+
+  mosart
+    derecho ----- OK
+    izumi ------- OK
+
+  rtm
+    derecho ----- OK
+
+Answer changes
+--------------
+
+Changes answers relative to baseline: Only time variable, plus read caveat
+
+  Summarize any changes to answers, i.e.,
+    - what code configurations: all
+    - what platforms/compilers: all
+    - nature of change: only the time variable
+
+ Caveat: We see diffs in mosart and cpl output that will be eliminated later in this series of "history" tags, in particular ctsm5.3.020. They are discussed here:
+https://github.com/ESCOMP/CTSM/pull/2838#issuecomment-2477608383
+https://github.com/ESCOMP/MOSART/issues/103#issuecomment-2479679014
+
+Other details
+-------------
+List any git submodules updated (cime, rtm, mosart, cism, fates, etc.):
+ rtm, mosart
+
+Pull Requests that document the changes (include PR ids):
+ https://github.com/ESCOMP/ctsm/pull/2838
+ https://github.com/ESCOMP/MOSART/pull/70
+ https://github.com/ESCOMP/RTM/issues/54
+ https://github.com/ESCOMP/MOSART/pull/106
+ https://github.com/ESCOMP/RTM/pull/39
+
+===============================================================
+===============================================================
 Tag name: ctsm5.3.017
 Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310)
 Date: Thu 09 Jan 2025 11:56:43 AM MST
diff --git a/doc/ChangeSum b/doc/ChangeSum
index 545a02ff25..51769e49a2 100644
--- a/doc/ChangeSum
+++ b/doc/ChangeSum
@@ -1,5 +1,6 @@
 Tag                   Who      Date  Summary
 ============================================================================================================================
+       ctsm5.3.018   slevis 01/10/2025 Change history time to be the middle of the time bounds
        ctsm5.3.017   slevis 01/09/2025 Merge tmp-241219 branch to master
 tmp-241219.n03.ctsm5.3.016  01/09/2025 Bug fix for izumi nag tests to pass (slevis)
 tmp-241219.n02.ctsm5.3.016  01/08/2025 FATES hydro test update (glemieux)
diff --git a/python/ctsm/crop_calendars/cropcal_module.py b/python/ctsm/crop_calendars/cropcal_module.py
index 719d352665..3ea084e1d2 100644
--- a/python/ctsm/crop_calendars/cropcal_module.py
+++ b/python/ctsm/crop_calendars/cropcal_module.py
@@ -443,10 +443,7 @@ def import_output(
         )
 
     # Convert time axis to integer year, saving original as 'cftime'
-    this_ds_gs = this_ds_gs.assign_coords(
-        {"cftime": this_ds["time_bounds"].isel({"hist_interval": 0})}
-    )
-    this_ds_gs = this_ds_gs.assign_coords({"time": [t.year for t in this_ds_gs["cftime"].values]})
+    this_ds_gs = convert_time_to_int_year(filename, this_ds, this_ds_gs)
 
     # Get number of harvests
     this_ds_gs["NHARVESTS"] = (this_ds_gs["GDDHARV_PERHARV"] > 0).sum(dim="mxharvests")
@@ -458,6 +455,35 @@ def import_output(
     return this_ds_gs, any_bad
 
 
+def convert_time_to_int_year(filename, this_ds, this_ds_gs):
+    """
+    Convert time axis to integer year, saving original as 'cftime'
+    """
+    if "time_bounds" in this_ds:
+        # Always true before PR #2838, when even files with all instantaneous variables got
+        # time_bounds saved. After that PR (and before the segregation of instantaneous and other
+        # variables onto separate files), files with an instantaneous variable first in their list
+        # do not get time_bounds saved.
+        this_ds_gs = this_ds_gs.assign_coords(
+            {"cftime": this_ds["time_bounds"].isel({"hist_interval": 0})}
+        )
+        this_ds_gs = this_ds_gs.assign_coords(
+            {"time": [t.year for t in this_ds_gs["cftime"].values]}
+        )
+    elif this_ds["time"].attrs["long_name"] == "time at end of time step":
+        # This is an "instantaneous file."
+        this_ds_gs = this_ds_gs.assign_coords({"cftime": this_ds["time"]})
+        this_ds_gs = this_ds_gs.assign_coords(
+            {"time": [t.year - 1 for t in this_ds_gs["cftime"].values]}
+        )
+    else:
+        raise RuntimeError(
+            f"{filename} is neither an instantaneous nor a combined/non-instantaneous file."
+        )
+
+    return this_ds_gs
+
+
 def handle_zombie_crops(this_ds):
     """
     When doing transient runs, it's somehow possible for crops in newly-active patches to be
diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90
index 381e1f1170..426fa2d7e0 100644
--- a/src/main/histFileMod.F90
+++ b/src/main/histFileMod.F90
@@ -1172,6 +1172,7 @@ subroutine htape_addfld (t, f, avgflag)
     integer :: beg1d,end1d          ! beginning and ending indices for this field (assume already set)
     integer :: num1d_out            ! history output 1d size
     type(bounds_type) :: bounds
+    character(len=avgflag_strlen) :: avgflag_temp  ! local copy of hist_avgflag_pertape(t)
     character(len=*),parameter :: subname = 'htape_addfld'
     !-----------------------------------------------------------------------
 
@@ -1302,6 +1303,19 @@ subroutine htape_addfld (t, f, avgflag)
        tape(t)%hlist(n)%avgflag = avgflag
     end if
 
+    ! Override this tape's avgflag if nhtfrq == 1
+    if (tape(t)%nhtfrq == 1) then  ! output is instantaneous
+       hist_avgflag_pertape(t) = 'I'
+    end if
+    ! Override this field's avgflag if the namelist or the previous line
+    ! has set this tape to
+    ! - instantaneous (I) or
+    ! - local time (L)
+    avgflag_temp = hist_avgflag_pertape(t)
+    if (avgflag_temp == 'I' .or. avgflag_temp(1:1) == 'L') then
+       tape(t)%hlist(n)%avgflag = avgflag_temp
+    end if
+
   end subroutine htape_addfld
 
   !-----------------------------------------------------------------------
@@ -3098,6 +3112,7 @@ subroutine htape_timeconst(t, mode)
     integer :: mcdate                     ! current date
     integer :: yr,mon,day,nbsec           ! year,month,day,seconds components of a date
     integer :: hours,minutes,secs         ! hours,minutes,seconds of hh:mm:ss
+    character(len= 12) :: step_or_bounds  ! string used in long_name of several time variables
     character(len= 10) :: basedate        ! base date (yyyymmdd)
     character(len=  8) :: basesec         ! base seconds
     character(len=  8) :: cdate           ! system date
@@ -3357,8 +3372,18 @@ subroutine htape_timeconst(t, mode)
 
        dim1id(1) = time_dimid
        str = 'days since ' // basedate // " " // basesec
-       call ncd_defvar(nfid(t), 'time', tape(t)%ncprec, 1, dim1id, varid, &
-            long_name='time',units=str)
+       if (hist_avgflag_pertape(t) /= 'I') then  ! NOT instantaneous fields tape
+          step_or_bounds = 'time_bounds'
+          long_name = 'time at exact middle of ' // step_or_bounds
+          call ncd_defvar(nfid(t), 'time', tape(t)%ncprec, 1, dim1id, varid, &
+               long_name=long_name, units=str)
+          call ncd_putatt(nfid(t), varid, 'bounds', 'time_bounds')
+       else  ! instantaneous fields tape
+          step_or_bounds = 'time step'
+          long_name = 'time at end of ' // step_or_bounds
+          call ncd_defvar(nfid(t), 'time', tape(t)%ncprec, 1, dim1id, varid, &
+               long_name=long_name, units=str)
+       end if
        cal = get_calendar()
        if (      trim(cal) == NO_LEAP_C   )then
           caldesc = "noleap"
@@ -3366,11 +3391,11 @@ subroutine htape_timeconst(t, mode)
           caldesc = "gregorian"
        end if
        call ncd_putatt(nfid(t), varid, 'calendar', caldesc)
-       call ncd_putatt(nfid(t), varid, 'bounds', 'time_bounds')
 
        dim1id(1) = time_dimid
+       long_name = 'current date (YYYYMMDD) at end of ' // step_or_bounds
        call ncd_defvar(nfid(t) , 'mcdate', ncd_int, 1, dim1id , varid, &
-          long_name = 'current date (YYYYMMDD)')
+          long_name = long_name)
        !
        ! add global attribute time_period_freq
        !
@@ -3397,18 +3422,23 @@ subroutine htape_timeconst(t, mode)
        call ncd_putatt(nfid(t), ncd_global, 'time_period_freq',          &
                           trim(time_period_freq))
 
+       long_name = 'current seconds of current date at end of ' // step_or_bounds
        call ncd_defvar(nfid(t) , 'mcsec' , ncd_int, 1, dim1id , varid, &
-          long_name = 'current seconds of current date', units='s')
+          long_name = long_name, units='s')
+       long_name = 'current day (from base day) at end of ' // step_or_bounds
        call ncd_defvar(nfid(t) , 'mdcur' , ncd_int, 1, dim1id , varid, &
-          long_name = 'current day (from base day)')
+          long_name = long_name)
+       long_name = 'current seconds of current day at end of ' // step_or_bounds
        call ncd_defvar(nfid(t) , 'mscur' , ncd_int, 1, dim1id , varid, &
-          long_name = 'current seconds of current day')
+          long_name = long_name)
        call ncd_defvar(nfid(t) , 'nstep' , ncd_int, 1, dim1id , varid, &
           long_name = 'time step')
 
        dim2id(1) = hist_interval_dimid;  dim2id(2) = time_dimid
-       call ncd_defvar(nfid(t), 'time_bounds', ncd_double, 2, dim2id, varid, &
-          long_name = 'history time interval endpoints')
+       if (hist_avgflag_pertape(t) /= 'I') then  ! NOT instantaneous fields tape
+          call ncd_defvar(nfid(t), 'time_bounds', ncd_double, 2, dim2id, varid, &
+             long_name = 'history time interval endpoints')
+       end if
 
        dim2id(1) = strlen_dimid;  dim2id(2) = time_dimid
        call ncd_defvar(nfid(t), 'date_written', ncd_char, 2, dim2id, varid)
@@ -3436,13 +3466,16 @@ subroutine htape_timeconst(t, mode)
        call ncd_io('mscur' , mscur , 'write', nfid(t), nt=tape(t)%ntimes)
        call ncd_io('nstep' , nstep , 'write', nfid(t), nt=tape(t)%ntimes)
 
-       time = mdcur + mscur/secspday
+       timedata(1) = tape(t)%begtime  ! beginning time
+       timedata(2) = mdcur + mscur/secspday  ! end time
+       if (hist_avgflag_pertape(t) /= 'I') then  ! NOT instantaneous fields tape
+          time = (timedata(1) + timedata(2)) * 0.5_r8
+          call ncd_io('time_bounds', timedata, 'write', nfid(t), nt=tape(t)%ntimes)
+       else
+          time = timedata(2)
+       end if
        call ncd_io('time'  , time  , 'write', nfid(t), nt=tape(t)%ntimes)
 
-       timedata(1) = tape(t)%begtime
-       timedata(2) = time
-       call ncd_io('time_bounds', timedata, 'write', nfid(t), nt=tape(t)%ntimes)
-
        call getdatetime (cdate, ctime)
        call ncd_io('date_written', cdate, 'write', nfid(t), nt=tape(t)%ntimes)