! $Id$
!
! Earth System Modeling Framework
! Copyright 2002-2003, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the GPL.
!
!==============================================================================
!
!     ESMF Time Module
      module ESMF_TimeMod
!
!==============================================================================
!
! This file contains the Time class definition and all Time class methods.
!
!------------------------------------------------------------------------------
! INCLUDES
#include "ESMF_TimeMgr.inc"

!==============================================================================
!BOPI
! !MODULE: ESMF_TimeMod
!
! !DESCRIPTION:
! Part of Time Manager F90 API wrapper of C++ implemenation
!
! Defines F90 wrapper entry points for corresponding
! C++ class {\tt ESMC\_Time} implementation
!
! See {\tt ../include/ESMC\_Time.h} for complete description
!
!------------------------------------------------------------------------------
! !USES:
      ! inherit from ESMF base class
      use ESMF_BaseMod

      ! inherit from base time class
      use ESMF_BaseTimeMod

      ! associated derived types
      use ESMF_TimeIntervalMod
      use ESMF_CalendarMod
      use ESMF_ShrTimeMod, only : ESMF_Time
! added by Jhe
      use ESMF_Stubs

      implicit none
!
!------------------------------------------------------------------------------
! !PRIVATE TYPES:
      private
!------------------------------------------------------------------------------
!     ! ESMF_Time
!
!     ! F90 class type to match C++ Time class in size only;
!     !  all dereferencing within class is performed by C++ implementation

! move to ESMF_ShrTimeMod
!     type ESMF_Time
!       type(ESMF_BaseTime) :: basetime           ! inherit base class
!       ! time instant is expressed as year + basetime
!       integer :: YR
!       type(ESMF_Calendar), pointer :: calendar  ! associated calendar
!     end type
!------------------------------------------------------------------------------
! !PUBLIC DATA:

!------------------------------------------------------------------------------
! !PUBLIC TYPES:
      public ESMF_Time
!------------------------------------------------------------------------------
!
! !PUBLIC MEMBER FUNCTIONS:
      public ESMF_TimeGet
      public ESMF_TimeSet
      public ESMF_TimePrint

! Required inherited and overridden ESMF_Base class methods

      public ESMF_TimeCopy
      public ESMF_SetYearWidth

! !PRIVATE MEMBER FUNCTIONS:

      private ESMF_TimeGetDayOfYear
      private ESMF_TimeGetDayOfYearInteger

! Inherited and overloaded from ESMF_BaseTime

      public operator(+)
      public ESMF_TimeInc

      public operator(-)
      private ESMF_TimeDec
      private ESMF_TimeDiff

      public operator(.EQ.)
      public ESMF_TimeEQ

      public operator(.NE.)
      public ESMF_TimeNE

      public operator(.LT.)
      public ESMF_TimeLT

      public operator(.GT.)
      public ESMF_TimeGT

      public operator(.LE.)
      public ESMF_TimeLE

      public operator(.GE.)
      public ESMF_TimeGE

!EOPI

!------------------------------------------------------------------------------
! The following line turns the CVS identifier string into a printable variable.
      character(*), parameter, private :: version = &
      '$Id$'

      integer :: yearWidth = 4

!==============================================================================
!
! INTERFACE BLOCKS
!
!==============================================================================
!BOP
! !INTERFACE:
      interface ESMF_TimeGetDayOfYear

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeGetDayOfYearInteger

! !DESCRIPTION:
!     This interface overloads the {\tt ESMF\_GetDayOfYear} method
!     for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(+)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeInc, ESMF_TimeInc2

! !DESCRIPTION:
!     This interface overloads the + operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface assignment (=)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeCopy

! !DESCRIPTION:
!     This interface overloads the = operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(-)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeDec, ESMF_TimeDec2

! !DESCRIPTION:
!     This interface overloads the - operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(-)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeDiff

! !DESCRIPTION:
!     This interface overloads the - operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(.EQ.)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeEQ

! !DESCRIPTION:
!     This interface overloads the .EQ. operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(.NE.)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeNE

! !DESCRIPTION:
!     This interface overloads the .NE. operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(.LT.)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeLT

! !DESCRIPTION:
!     This interface overloads the .LT. operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(.GT.)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeGT

! !DESCRIPTION:
!     This interface overloads the .GT. operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(.LE.)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeLE

! !DESCRIPTION:
!     This interface overloads the .LE. operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !INTERFACE:
      interface operator(.GE.)

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeGE

! !DESCRIPTION:
!     This interface overloads the .GE. operator for the {\tt ESMF\_Time} class
!
!EOP
      end interface
!
!------------------------------------------------------------------------------

!==============================================================================

      contains

!==============================================================================
!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeGet - Get value in user-specified units

! !INTERFACE:
!      subroutine ESMF_TimeGet(time, YY, YRl, MM, DD, D, Dl, H, M, S, Sl, MS, &
!                              US, NS, d_, h_, m_, s_, ms_, us_, ns_, Sn, Sd, &
!                              dayOfYear, dayOfYear_r8, dayOfYear_intvl,      &
!                              timeString, rc)

recursive subroutine ESMF_TimeGet(time, YY, MM, DD, D, Dl, H, M, S, MS, &
                              Sn, Sd, &
                              dayOfYear, dayOfYear_r8, dayOfYear_intvl,      &
                              timeString, rc)

! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time
      integer, intent(out), optional :: YY
!      integer(ESMF_KIND_I8), intent(out), optional :: YRl
      integer, intent(out), optional :: MM
      integer, intent(out), optional :: DD
      integer, intent(out), optional :: D
      integer(ESMF_KIND_I8), intent(out), optional :: Dl
      integer, intent(out), optional :: H
      integer, intent(out), optional :: M
      integer, intent(out), optional :: S
!      integer(ESMF_KIND_I8), intent(out), optional :: Sl
      integer, intent(out), optional :: MS
!      integer, intent(out), optional :: US
!      integer, intent(out), optional :: NS
!      double precision, intent(out), optional :: d_
!      double precision, intent(out), optional :: h_
!      double precision, intent(out), optional :: m_
!      double precision, intent(out), optional :: s_
!      double precision, intent(out), optional :: ms_
!      double precision, intent(out), optional :: us_
!      double precision, intent(out), optional :: ns_
      integer, intent(out), optional :: Sn
      integer, intent(out), optional :: Sd
      integer, intent(out), optional :: dayOfYear
      real(ESMF_KIND_R8), intent(out), optional :: dayOfYear_r8
      character (len=*), intent(out), optional :: timeString
      type(ESMF_TimeInterval), intent(out), optional :: dayOfYear_intvl
      integer, intent(out), optional :: rc


! !DESCRIPTION:
!     Get the value of the {\tt ESMF\_Time} in units specified by the user
!     via F90 optional arguments.
!
!     Time manager represents and manipulates time internally with integers
!     to maintain precision. Hence, user-specified floating point values are
!     converted internally from integers.
!
!     See {\tt ../include/ESMC\_BaseTime.h and ../include/ESMC\_Time.h} for
!     complete description.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to query
!     \item[{[YY]}]
!          Integer year CCYR (>= 32-bit)
!     \item[{[YRl]}]
!          Integer year CCYR (large, >= 64-bit)
!     \item[{[MM]}]
!          Integer month 1-12
!     \item[{[DD]}]
!          Integer day of the month 1-31
!     \item[{[D]}]
!          Integer Julian days (>= 32-bit)
!     \item[{[Dl]}]
!          Integer Julian days (large, >= 64-bit)
!     \item[{[H]}]
!          Integer hours
!     \item[{[M]}]
!          Integer minutes
!     \item[{[S]}]
!          Integer seconds (>= 32-bit)
!     \item[{[Sl]}]
!          Integer seconds (large, >= 64-bit)
!     \item[{[MS]}]
!          Integer milliseconds
!     \item[{[US]}]
!          Integer microseconds
!     \item[{[NS]}]
!          Integer nanoseconds
!     \item[{[d\_]}]
!          Double precision days
!     \item[{[h\_]}]
!          Double precision hours
!     \item[{[m\_]}]
!          Double precision minutes
!     \item[{[s\_]}]
!          Double precision seconds
!     \item[{[ms\_]}]
!          Double precision milliseconds
!     \item[{[us\_]}]
!          Double precision microseconds
!     \item[{[ns\_]}]
!          Double precision nanoseconds
!     \item[{[Sn]}]
!          Integer fractional seconds - numerator
!     \item[{[Sd]}]
!          Integer fractional seconds - denominator
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG2.1, TMG2.5.1, TMG2.5.6
!EOP
      type(ESMF_TimeInterval) :: day_step
      integer :: ierr
      TYPE(ESMF_Time) :: begofyear
      TYPE(ESMF_TimeInterval) :: difftobegofyear
      INTEGER :: year, month, dayofmonth, hour, minute, second
      INTEGER :: i
      INTEGER(ESMF_KIND_I8) :: cnt

      ierr = ESMF_SUCCESS

      IF ( PRESENT( YY ) ) THEN
        YY = time%YR
      ENDIF
      IF ( PRESENT( MM ) ) THEN
        CALL timegetmonth( time, MM )
      ENDIF
      IF ( PRESENT( DD ) ) THEN
        CALL timegetdayofmonth( time, DD )
      ENDIF

      if (present(d) .or. present(dl)) then
        cnt = 0
        do i = 0,time%yr-1
           cnt = cnt + ndaysinyear(i,time%calendar%type)
        enddo
        do i = time%yr,-1
           cnt = cnt - ndaysinyear(i,time%calendar%type)
        enddo
        call timegetmonth(time,month)
        do i = 1,month-1
           cnt = cnt + ndaysinmonth(time%yr,i,time%calendar%type)
        enddo
        call timegetdayofmonth( time, dayofmonth)
        cnt = cnt + dayofmonth
        if (present(d)) then
          d = cnt
        endif
        if (present(dl)) then
          dl = cnt
        endif
      endif
!
!$$$ push HMS down into ESMF_BaseTime
      IF ( PRESENT( H ) ) THEN
        H = mod( time%basetime%S, SECONDS_PER_DAY ) / SECONDS_PER_HOUR
      ENDIF
      IF ( PRESENT( M ) ) THEN
        M = mod( time%basetime%S, SECONDS_PER_HOUR) / SECONDS_PER_MINUTE
      ENDIF
      IF ( PRESENT( S ) ) THEN
        S = mod( time%basetime%S, SECONDS_PER_MINUTE )
      ENDIF

      IF ( PRESENT( S ) .AND. PRESENT( DD ) ) THEN
        IF ( ( .NOT. PRESENT( H ) ) .AND. ( .NOT. PRESENT( M ) ) ) THEN
          S = mod( time%basetime%S, SECONDS_PER_DAY )
        ENDIF
      ENDIF
      IF ( PRESENT( MS ) ) THEN
        IF ( time%basetime%Sd /= 0 ) THEN
          MS = NINT( ( time%basetime%Sn*1.0D0 / time%basetime%Sd*1.0D0 ) * 1000.0D0 )
        ELSE
          MS = 0
        ENDIF
      ENDIF
      IF ( PRESENT( Sd ) .AND. PRESENT( Sn ) ) THEN
        Sd = time%basetime%Sd
        Sn = time%basetime%Sn
      ENDIF
      IF ( PRESENT( dayOfYear ) ) THEN
        CALL ESMF_TimeGetDayOfYear( time, dayOfYear, rc=ierr )
      ENDIF
      IF ( PRESENT( timeString ) ) THEN
        ! This duplication for YMD is an optimization that avoids calling
        ! timegetmonth() and timegetdayofmonth() when it is not needed.
        year = time%YR
        CALL timegetmonth( time, month )
        CALL timegetdayofmonth( time, dayofmonth )
!$$$ push HMS down into ESMF_BaseTime
        hour = mod( time%basetime%S, SECONDS_PER_DAY ) / SECONDS_PER_HOUR
        minute = mod( time%basetime%S, SECONDS_PER_HOUR) / SECONDS_PER_MINUTE
        second = mod( time%basetime%S, SECONDS_PER_MINUTE )
        CALL ESMFold_TimeGetString( year, month, dayofmonth, &
                                    hour, minute, second, timeString )
      ENDIF
      IF ( PRESENT( dayOfYear_intvl ) ) THEN
        year = time%YR
        CALL ESMF_TimeSet( begofyear, yy=year, mm=1, dd=1, s=0, &
                           calendar=time%calendar, rc=ierr )
        IF ( ierr == ESMF_FAILURE)THEN
           rc = ierr
           RETURN
        END IF
        dayOfYear_intvl = time - begofyear
      ENDIF
      IF ( PRESENT( dayOfYear_r8) ) THEN
        year = time%YR
        CALL ESMF_TimeSet( begofyear, yy=year, mm=1, dd=1, s=0, &
                           calendar=time%calendar, rc=ierr )
        IF ( ierr == ESMF_FAILURE)THEN
           rc = ierr
           RETURN
        END IF
        CALL ESMF_TimeIntervalSet( day_step, d=1, s=0, rc=ierr )
        IF ( ierr == ESMF_FAILURE)THEN
           rc = ierr
           RETURN
        END IF
        difftobegofyear = time - begofyear + day_step
        CALL ESMF_TimeIntervalGet( difftobegofyear, d_r8=dayOfYear_r8, rc=ierr )
        IF ( ierr == ESMF_FAILURE)THEN
           rc = ierr
           RETURN
        END IF
      ENDIF

      IF ( PRESENT( rc ) ) THEN
        rc = ierr
      ENDIF

      end subroutine ESMF_TimeGet

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeSet - Initialize via user-specified unit set

! !INTERFACE:
!      subroutine ESMF_TimeSet(time, YY, YRl, MM, DD, D, Dl, H, M, S, Sl, &
!                              MS, US, NS, d_, h_, m_, s_, ms_, us_, ns_, &
!                              Sn, Sd, calendar, calkindflag, rc)

      subroutine ESMF_TimeSet(time, YY, MM, DD, D, Dl, H, M, S, &
                              MS, &
                              Sn, Sd, calendar, calkindflag, rc)

! !ARGUMENTS:
      type(ESMF_Time), intent(inout) :: time
      integer, intent(in), optional :: YY
!      integer(ESMF_KIND_I8), intent(in), optional :: YRl
      integer, intent(in), optional :: MM
      integer, intent(in), optional :: DD
      integer, intent(in), optional :: D
      integer(ESMF_KIND_I8), intent(in), optional :: Dl
      integer, intent(in), optional :: H
      integer, intent(in), optional :: M
      integer, intent(in), optional :: S
!      integer(ESMF_KIND_I8), intent(in), optional :: Sl
      integer, intent(in), optional :: MS
!      integer, intent(in), optional :: US
!      integer, intent(in), optional :: NS
!      double precision, intent(in), optional :: d_
!      double precision, intent(in), optional :: h_
!      double precision, intent(in), optional :: m_
!      double precision, intent(in), optional :: s_
!      double precision, intent(in), optional :: ms_
!      double precision, intent(in), optional :: us_
!      double precision, intent(in), optional :: ns_
      integer, intent(in), optional :: Sn
      integer, intent(in), optional :: Sd
      type(ESMF_Calendar), intent(in), target, optional :: calendar
      type(ESMF_CalKind_Flag), intent(in),  optional :: calkindflag
      integer, intent(out), optional :: rc

      ! locals
      INTEGER :: ierr
      logical :: dset

! !DESCRIPTION:
!     Initializes a {\tt ESMF\_Time} with a set of user-specified units
!     via F90 optional arguments.
!
!     Time manager represents and manipulates time internally with integers
!     to maintain precision. Hence, user-specified floating point values are
!     converted internally to integers.
!
!     See {\tt ../include/ESMC\_BaseTime.h and ../include/ESMC\_Time.h} for
!     complete description.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to initialize
!     \item[{[YY]}]
!          Integer year CCYR (>= 32-bit)
!     \item[{[YRl]}]
!          Integer year CCYR (large, >= 64-bit)
!     \item[{[MM]}]
!          Integer month 1-12
!     \item[{[DD]}]
!          Integer day of the month 1-31
!     \item[{[D]}]
!          Integer Julian days (>= 32-bit)
!     \item[{[Dl]}]
!          Integer Julian days (large, >= 64-bit)
!     \item[{[H]}]
!          Integer hours
!     \item[{[M]}]
!          Integer minutes
!     \item[{[S]}]
!          Integer seconds (>= 32-bit)
!     \item[{[Sl]}]
!          Integer seconds (large, >= 64-bit)
!     \item[{[MS]}]
!          Integer milliseconds
!     \item[{[US]}]
!          Integer microseconds
!     \item[{[NS]}]
!          Integer nanoseconds
!     \item[{[d\_]}]
!          Double precision days
!     \item[{[h\_]}]
!          Double precision hours
!     \item[{[m\_]}]
!          Double precision minutes
!     \item[{[s\_]}]
!          Double precision seconds
!     \item[{[ms\_]}]
!          Double precision milliseconds
!     \item[{[us\_]}]
!          Double precision microseconds
!     \item[{[ns\_]}]
!          Double precision nanoseconds
!     \item[{[Sn]}]
!          Integer fractional seconds - numerator
!     \item[{[Sd]}]
!          Integer fractional seconds - denominator
!     \item[{[cal]}]
!          Associated {\tt Calendar}
!     \item[{[tz]}]
!          Associated timezone (hours offset from GMT, e.g. EST = -5)
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMGn.n.n
!EOP
!  PRINT *,'DEBUG:  BEGIN ESMF_TimeSet()'
!$$$ push this down into ESMF_BaseTime constructor

      IF ( PRESENT( rc ) ) then
        rc = ESMF_FAILURE
      ENDIF

      time%YR = 0
      time%basetime%S  = 0
      time%basetime%Sn = 0
      time%basetime%Sd = 0

      IF ( PRESENT(calendar) )THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  using passed-in calendar'
        IF ( .not. ESMF_CalendarInitialized( calendar ) )THEN
           call wrf_error_fatal( "Error:: ESMF_CalendarCreate not "// &
                                 "called on input Calendar")
        END IF
!        call flush(6)
!        write(6,*) 'tcx1 ESMF_TimeSet point to calendar'
!        call flush(6)
        time%Calendar => calendar
      ELSE
!  PRINT *,'DEBUG:  ESMF_TimeSet():  using default calendar'
! for the sake of WRF, check ESMF_IsInitialized, revised by Juanxiong He
        IF ( .not. ESMF_IsInitialized() )THEN
           call wrf_error_fatal( "Error:: ESMF_Initialize not called")
        END IF
!        IF ( .not. ESMF_CalendarInitialized( defaultCal ) )THEN
!           call wrf_error_fatal( "Error:: ESMF_Initialize not called")
!        END IF
        if (present(calkindflag)) then
!           write(6,*) 'tcx2 ESMF_TimeSet point to calendarkindflag',calkindflag%caltype
!           call flush(6)
           if (calkindflag%caltype == ESMF_CALKIND_GREGORIAN%caltype) then
              time%Calendar => gregorianCal
           elseif (calkindflag%caltype == ESMF_CALKIND_NOLEAP%caltype) then
              time%Calendar => noleapCal
           else
              call wrf_error_fatal( "Error:: ESMF_TimeSet invalid calkindflag")
           endif
        else
!           write(6,*) 'tcx3 ESMF_TimeSet point to defaultcal'
!           call flush(6)
           time%Calendar => defaultCal
        endif
      END IF
!      write(6,*) 'tcxn ESMF_TimeSet ',ESMF_CALKIND_NOLEAP%caltype
!      call flush(6)
!      write(6,*) 'tcxg ESMF_TimeSet ',ESMF_CALKIND_GREGORIAN%caltype
!      call flush(6)
!      write(6,*) 'tcxt ESMF_TimeSet ',time%calendar%type%caltype
!      call flush(6)

      dset = .false.
      if (present(D)) then
         if (present(Dl)) CALL wrf_error_fatal( 'ESMF_TimeSet:  D and Dl not both valid')
         time%basetime%s = SECONDS_PER_DAY * INT(D-1,ESMF_KIND_I8)
         dset=.true.
      elseif (present(Dl)) then
         time%basetime%s = SECONDS_PER_DAY * Dl-1_ESMF_KIND_I8
         dset=.true.
      endif

      IF ( PRESENT( YY ) ) THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  YY = ',YY
        if (dset) CALL wrf_error_fatal( 'ESMF_TimeSet:  D or DL and YY,MM,DD not both valid')
        time%YR = YY
      ENDIF
      IF ( PRESENT( MM ) ) THEN
        if (dset) CALL wrf_error_fatal( 'ESMF_TimeSet:  D or DL and YY,MM,DD not both valid')
!  PRINT *,'DEBUG:  ESMF_TimeSet():  MM = ',MM
        CALL timeaddmonths( time, MM, ierr )
        IF ( ierr == ESMF_FAILURE ) THEN
          IF ( PRESENT( rc ) ) THEN
            rc = ESMF_FAILURE
            RETURN
          ELSE
            CALL wrf_error_fatal( 'ESMF_TimeSet:  MM out of range' )
          ENDIF
        ENDIF
!  PRINT *,'DEBUG:  ESMF_TimeSet():  back from timeaddmonths'
      ENDIF
      IF ( PRESENT( DD ) ) THEN
        if (dset) CALL wrf_error_fatal( 'ESMF_TimeSet:  D or DL and YY,MM,DD not both valid')
!$$$ no check for DD in range of days of month MM yet
!$$$ Must separate D and DD for correct interface!
!  PRINT *,'DEBUG:  ESMF_TimeSet():  DD = ',DD
        time%basetime%S = time%basetime%S + &
          ( SECONDS_PER_DAY * INT( (DD-1), ESMF_KIND_I8 ) )
      ENDIF
!$$$ push H,M,S,Sn,Sd,MS down into ESMF_BaseTime constructor
      IF ( PRESENT( H ) ) THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  H = ',H
        time%basetime%S = time%basetime%S + &
          ( SECONDS_PER_HOUR * INT( H, ESMF_KIND_I8 ) )
      ENDIF
      IF ( PRESENT( M ) ) THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  M = ',M
        time%basetime%S = time%basetime%S + &
          ( SECONDS_PER_MINUTE * INT( M, ESMF_KIND_I8 ) )
      ENDIF
      IF ( PRESENT( S ) ) THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  S = ',S
        time%basetime%S = time%basetime%S + &
          INT( S, ESMF_KIND_I8 )
      ENDIF
      IF ( PRESENT( Sn ) .AND. ( .NOT. PRESENT( Sd ) ) ) THEN
        CALL wrf_error_fatal( &
          "ESMF_TimeSet:  Must specify Sd if Sn is specified")
      ENDIF
      IF ( PRESENT( Sd ) .AND. PRESENT( MS ) ) THEN
        CALL wrf_error_fatal( &
          "ESMF_TimeSet:  Must not specify both Sd and MS")
      ENDIF
      time%basetime%Sn = 0
      time%basetime%Sd = 0
      IF ( PRESENT( MS ) ) THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  MS = ',MS
        time%basetime%Sn = MS
        time%basetime%Sd = 1000_ESMF_KIND_I8
      ELSE IF ( PRESENT( Sd ) ) THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  Sd = ',Sd
        time%basetime%Sd = Sd
        IF ( PRESENT( Sn ) ) THEN
!  PRINT *,'DEBUG:  ESMF_TimeSet():  Sn = ',Sn
          time%basetime%Sn = Sn
        ENDIF
      ENDIF

!  PRINT *,'DEBUG:  ESMF_TimeSet():  calling normalize_time()'
!$$$DEBUG
!IF ( time%basetime%Sd > 0 ) THEN
!  PRINT *,'DEBUG ESMF_TimeSet() before normalize:  S,Sn,Sd = ', &
!    time%basetime%S, time%basetime%Sn, time%basetime%Sd
!ENDIF
!$$$END DEBUG
      CALL normalize_time( time )
!$$$DEBUG
!IF ( time%basetime%Sd > 0 ) THEN
!  PRINT *,'DEBUG ESMF_TimeSet() after normalize:  S,Sn,Sd = ', &
!    time%basetime%S, time%basetime%Sn, time%basetime%Sd
!ENDIF
!$$$END DEBUG

!  PRINT *,'DEBUG:  ESMF_TimeSet():  back from normalize_time()'
      IF ( PRESENT( rc ) ) THEN
        rc = ESMF_SUCCESS
      ENDIF

      end subroutine ESMF_TimeSet

!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMFold_TimeGetString - Get time instant value in string format

! !INTERFACE:
      subroutine ESMFold_TimeGetString( year, month, dayofmonth, &
                                        hour, minute, second, TimeString )

! !ARGUMENTS:
      integer, intent(in) :: year
      integer, intent(in) :: month
      integer, intent(in) :: dayofmonth
      integer, intent(in) :: hour
      integer, intent(in) :: minute
      integer, intent(in) :: second
      character*(*), intent(out) :: TimeString
      character*(256) :: TimeFormatString
! !DESCRIPTION:
!     Convert {\tt ESMF\_Time}'s value into ISO 8601 format YYYY-MM-DDThh:mm:ss
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to convert
!     \item[TimeString]
!          The string to return
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG2.4.7
!EOP

!PRINT *,'DEBUG:  ESMF_TimePrint():  YR,S,Sn,Sd = ',time%YR,time%basetime%S,time%basetime%Sn,time%basetime%Sd
!PRINT *,'DEBUG:  ESMF_TimePrint():  year = ',year
!PRINT *,'DEBUG:  ESMF_TimePrint():  month, dayofmonth = ',month,dayofmonth
!PRINT *,'DEBUG:  ESMF_TimePrint():  hour = ',hour
!PRINT *,'DEBUG:  ESMF_TimePrint():  minute = ',minute
!PRINT *,'DEBUG:  ESMF_TimePrint():  second = ',second

!$$$here...  add negative sign for YR<0
!$$$here...  add Sn, Sd ??
      write(TimeFormatString,FMT="(A,I4.4,A,I4.4,A)") &
           "(I", yearWidth, ".", yearWidth, ",'-',I2.2,'-',I2.2,'_',I2.2,':',I2.2,':',I2.2)"
      write(TimeString,FMT=TimeFormatString) year,month,dayofmonth,hour,minute,second

      end subroutine ESMFold_TimeGetString

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeGetDayOfYearInteger - Get time instant's day of the year as an integer value
!
! !INTERFACE:
      subroutine ESMF_TimeGetDayOfYearInteger(time, DayOfYear, rc)
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time
      integer, intent(out) :: DayOfYear
      integer, intent(out), optional :: rc
!
! !DESCRIPTION:
!     Get the day of the year the given {\tt ESMF\_Time} instant falls on
!     (1-365).  Returned as an integer value
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to query
!     \item[DayOfYear]
!          The {\tt ESMF\_Time} instant's day of the year (1-365)
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!EOP
      ! requires that time be normalized
!$$$ bug when Sn>0?  test
!$$$ add tests
      DayOfYear = ( time%basetime%S / SECONDS_PER_DAY ) + 1
      IF ( PRESENT( rc ) ) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeGetDayOfYearInteger

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeInc - Increment time instant with a time interval
!
! !INTERFACE:
   function ESMF_TimeInc(time, timeinterval)
!
! !RETURN VALUE:
      type(ESMF_Time) :: ESMF_TimeInc
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time
      type(ESMF_TimeInterval), intent(in) :: timeinterval
! !LOCAL:
      INTEGER :: year,month,day,sec,nmon,nyr,mpyi4
!
! !DESCRIPTION:
!     Increment {\tt ESMF\_Time} instant with a {\tt ESMF\_TimeInterval},
!     return resulting {\tt ESMF\_Time} instant
!
!     Maps overloaded (+) operator interface function to
!     {\tt ESMF\_BaseTime} base class
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The given {\tt ESMF\_Time} to increment
!     \item[timeinterval]
!          The {\tt ESMF\_TimeInterval} to add to the given {\tt ESMF\_Time}
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.4, TMG2.4.4, TMG2.4.5, TMG2.4.6, TMG5.1, TMG5.2, TMG7.2
!EOP

      mpyi4 = MONTHS_PER_YEAR

      ! copy ESMF_Time specific properties (e.g. calendar, timezone)

      ESMF_TimeInc = time
!      write(6,*) 'tcx timeinc1 ',ESMF_TimeInc%yr,ESMF_TimeInc%basetime%s
      CALL normalize_time( ESMF_TimeInc )

!      write(6,*) 'tcx timeint ',timeinterval%yr,timeinterval%mm,timeinterval%basetime%s

      ! add years and months by manually forcing incremental years then adjusting the day of
      ! the month at the end if it's greater than the number of days in the month
      ! esmf seems to do exactly this based on testing

      nmon = timeinterval%mm
      nyr  = timeinterval%yr
      if (abs(nmon) > 0 .or. abs(nyr) > 0) then
         call ESMF_TimeGet(ESMF_TimeInc,yy=year,mm=month,dd=day,s=sec)
!         write(6,*) 'tcx timeinc mon1 ',year,month,day,sec,nyr,nmon
         year  = year  + nyr
         month = month + nmon
         do while (month > MONTHS_PER_YEAR)
            month = month - mpyi4
            year = year + 1
         enddo
         do while (month < 1)
            month = month + mpyi4
            year = year - 1
         enddo
!         write(6,*) 'tcx timeinc mon2 ',year,month,day,sec
         day = min(day,ndaysinmonth(year,month,ESMF_TimeInc%calendar%type))
         call ESMF_TimeSet(ESMF_TimeInc,yy=year,mm=month,dd=day,s=sec,calkindflag=time%calendar%type)
         call ESMF_TimeGet(ESMF_TimeInc,yy=year,mm=month,dd=day,s=sec)
!         write(6,*) 'tcx timeinc mon3 ',nmon,year,month,day,sec
      endif

      ! finally add seconds

!      write(6,*) 'tcx timeinc sec ',ESMF_TimeInc%basetime%s,timeinterval%basetime%s
      ESMF_TimeInc%basetime = ESMF_TimeInc%basetime + timeinterval%basetime

      ! and normalize

!      write(6,*) 'tcx timeinc2p ',ESMF_TimeInc%yr,ESMF_TimeInc%basetime%s

      CALL normalize_time( ESMF_TimeInc )

!      write(6,*) 'tcx timeinc2 ',ESMF_TimeInc%yr,ESMF_TimeInc%basetime%s

   end function ESMF_TimeInc

! this is added for certain compilers that don't deal with commutativity

   function ESMF_TimeInc2(timeinterval, time)
      type(ESMF_Time) :: ESMF_TimeInc2
      type(ESMF_Time), intent(in) :: time
      type(ESMF_TimeInterval), intent(in) :: timeinterval
      ESMF_TimeInc2 = ESMF_TimeInc( time, timeinterval )
   end function ESMF_TimeInc2

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeDec - Decrement time instant with a time interval
!
! !INTERFACE:
   function ESMF_TimeDec(time, timeinterval)
!
! !RETURN VALUE:
      type(ESMF_Time) :: ESMF_TimeDec
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time
      type(ESMF_TimeInterval), intent(in) :: timeinterval
! !LOCAL:
      TYPE (ESMF_TimeInterval)  :: neginterval

! !DESCRIPTION:
!     Decrement {\tt ESMF\_Time} instant with a {\tt ESMF\_TimeInterval},
!     return resulting {\tt ESMF\_Time} instant
!
!     Maps overloaded (-) operator interface function to
!     {\tt ESMF\_BaseTime} base class
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The given {\tt ESMF\_Time} to decrement
!     \item[timeinterval]
!          The {\tt ESMF\_TimeInterval} to subtract from the given
!          {\tt ESMF\_Time}
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.4, TMG2.4.4, TMG2.4.5, TMG2.4.6, TMG5.1, TMG5.2, TMG7.2
!EOP

      ESMF_TimeDec = time

      neginterval = timeinterval
!$$$push this down into a unary negation operator on TimeInterval
      neginterval%basetime%S = -neginterval%basetime%S
      neginterval%basetime%Sn = -neginterval%basetime%Sn
      neginterval%YR = -neginterval%YR
      neginterval%MM = -neginterval%MM
      ESMF_TimeDec = time + neginterval

   end function ESMF_TimeDec

!
! this is added for certain compilers that don't deal with commutativity
!
   function ESMF_TimeDec2(timeinterval, time)
      type(ESMF_Time) :: ESMF_TimeDec2
      type(ESMF_Time), intent(in) :: time
      type(ESMF_TimeInterval), intent(in) :: timeinterval
      ESMF_TimeDec2 = ESMF_TimeDec( time, timeinterval )
   end function ESMF_TimeDec2
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeDiff - Return the difference between two time instants
!
! !INTERFACE:
   function ESMF_TimeDiff(time1, time2)
!
! !RETURN VALUE:
      type(ESMF_TimeInterval) :: ESMF_TimeDiff
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2
! !LOCAL:
      TYPE(ESMF_BaseTime) :: cmptime, zerotime
      integer :: yr
      integer :: y1,m1,d1,s1,y2,m2,d2,s2
      integer :: rc

! !DESCRIPTION:
!     Return the {\tt ESMF\_TimeInterval} difference between two
!     {\tt ESMF\_Time} instants, time1 - time2
!
!     Maps overloaded (-) operator interface function to
!     {\tt ESMF\_BaseTime} base class
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          The first {\tt ESMF\_Time} instant
!     \item[time2]
!          The second {\tt ESMF\_Time} instant
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.4, TMG2.4.4, TMG2.4.5, TMG2.4.6, TMG5.1, TMG5.2, TMG7.2
!EOP

      CALL ESMF_TimeIntervalSet( ESMF_TimeDiff, rc=rc )

      ESMF_TimeDiff%StartTime = time2
      ESMF_TimeDiff%StartTime_set = .true.

!      write(6,*) 'tcx timediff1 ',time2%yr,time2%basetime%s,time2%calendar%type%caltype
!      write(6,*) 'tcx timediff2 ',time1%yr,time1%basetime%s,time1%calendar%type%caltype

      call ESMF_TimeGet(time2,yy=y2,mm=m2,dd=d2,s=s2)
      call ESMF_TimeGet(time1,yy=y1,mm=m1,dd=d1,s=s1)

      ! Can either be yr/month based diff if diff is only in year and month
      ! or absolute seconds if diff in day/seconds as well
      !
      ! Update: Actually, the timeintcmp() routine in ESMF_TimeIntervalMod.F90 is not capable
      !    of comparing time intervals when one interval has a different year and month than
      !    the other. So, it is best here to always compute the interval as day/seconds.

!      if (d1 == d2 .and. s1 == s2) then
!!         write(6,*) 'tcx timedifft ym'
!         ESMF_TimeDiff%YR = y1 - y2
!         ESMF_TimeDiff%MM = m1 - m2
!         cmptime%S  = 0
!         cmptime%Sn = 0
!         cmptime%Sd = 0
!         ESMF_TimeDiff%basetime = cmptime
!      else
!         write(6,*) 'tcx timedifft sec'
         ESMF_TimeDiff%YR = 0
         ESMF_TimeDiff%MM = 0
         ESMF_TimeDiff%basetime = time1%basetime - time2%basetime
         IF ( time1%YR > time2%YR ) THEN
            DO yr = time2%YR, ( time1%YR - 1 )
!              write(6,*) 'tcx timediff3 ',yr,nsecondsinyear(yr,time2%calendar%type)
              ESMF_TimeDiff%basetime%S = ESMF_TimeDiff%basetime%S + nsecondsinyear(yr,time2%calendar%type)
            ENDDO
         ELSE IF ( time2%YR > time1%YR ) THEN
            DO yr = time1%YR, ( time2%YR - 1 )
!              write(6,*) 'tcx timediff4 ',yr,nsecondsinyear(yr,time2%calendar%type)
              ESMF_TimeDiff%basetime%S = ESMF_TimeDiff%basetime%S - nsecondsinyear(yr,time2%calendar%type)
            ENDDO
         ENDIF
!      endif

!      write(6,*) 'tcx timediff5 ',ESMF_TimeDiff%YR, ESMF_TimeDiff%MM, ESMF_TimeDiff%basetime%s

      CALL normalize_timeint( ESMF_TimeDiff )

!      write(6,*) 'tcx timediff6 ',ESMF_TimeDiff%YR, ESMF_TimeDiff%MM, ESMF_TimeDiff%basetime%s

   end function ESMF_TimeDiff

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeEQ - Compare two times for equality
!
! !INTERFACE:
      function ESMF_TimeEQ(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeEQ
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2
!
! !DESCRIPTION:
!     Return true if both given {\tt ESMF\_Time} instants are equal, false
!     otherwise.  Maps overloaded (==) operator interface function to
!     {\tt ESMF\_BaseTime} base class.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First time instant to compare
!     \item[time2]
!          Second time instant to compare
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.3, TMG2.4.3, TMG7.2
!EOP

      integer :: res

      call timecmp(time1,time2,res)
      ESMF_TimeEQ = (res .EQ. 0)

      end function ESMF_TimeEQ

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeNE - Compare two times for non-equality
!
! !INTERFACE:
      function ESMF_TimeNE(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeNE
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2

! !DESCRIPTION:
!     Return true if both given {\tt ESMF\_Time} instants are not equal, false
!     otherwise.  Maps overloaded (/=) operator interface function to
!     {\tt ESMF\_BaseTime} base class.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First time instant to compare
!     \item[time2]
!          Second time instant to compare
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.3, TMG2.4.3, TMG7.2
!EOP

      integer :: res

      call timecmp(time1,time2,res)
      ESMF_TimeNE = (res .NE. 0)

      end function ESMF_TimeNE

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeLT - Time instant 1 less than time instant 2 ?
!
! !INTERFACE:
      function ESMF_TimeLT(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeLT
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2
!
! !DESCRIPTION:
!     Return true if first {\tt ESMF\_Time} instant is less than second
!     {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (<)
!     operator interface function to {\tt ESMF\_BaseTime} base class.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First time instant to compare
!     \item[time2]
!          Second time instant to compare
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.3, TMG2.4.3, TMG7.2
!EOP

      integer :: res

      call timecmp(time1,time2,res)
      ESMF_TimeLT = (res .LT. 0)

      end function ESMF_TimeLT

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeGT - Time instant 1 greater than time instant 2 ?
!
! !INTERFACE:
      function ESMF_TimeGT(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeGT
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2
!
! !DESCRIPTION:
!     Return true if first {\tt ESMF\_Time} instant is greater than second
!     {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (>) operator
!     interface function to {\tt ESMF\_BaseTime} base class.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First time instant to compare
!     \item[time2]
!          Second time instant to compare
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.3, TMG2.4.3, TMG7.2
!EOP

      integer :: res

      call timecmp(time1,time2,res)
      ESMF_TimeGT = (res .GT. 0)

      end function ESMF_TimeGT

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeLE - Time instant 1 less than or equal to time instant 2 ?
!
! !INTERFACE:
      function ESMF_TimeLE(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeLE
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2
!
! !DESCRIPTION:
!     Return true if first {\tt ESMF\_Time} instant is less than or equal to
!     second {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (<=)
!     operator interface function to {\tt ESMF\_BaseTime} base class.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First time instant to compare
!     \item[time2]
!          Second time instant to compare
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.3, TMG2.4.3, TMG7.2
!EOP

      integer :: res

      call timecmp(time1,time2,res)
      ESMF_TimeLE = (res .LE. 0)

      end function ESMF_TimeLE

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_TimeGE - Time instant 1 greater than or equal to time instant 2 ?
!
! !INTERFACE:
      function ESMF_TimeGE(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeGE
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2
!
! !DESCRIPTION:
!     Return true if first {\tt ESMF\_Time} instant is greater than or equal to
!     second {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (>=)
!     operator interface function to {\tt ESMF\_BaseTime} base class.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First time instant to compare
!     \item[time2]
!          Second time instant to compare
!     \end{description}
!
! !REQUIREMENTS:
!     TMG1.5.3, TMG2.4.3, TMG7.2
!EOP

      integer :: res

      call timecmp(time1,time2,res)
      ESMF_TimeGE = (res .GE. 0)

      end function ESMF_TimeGE

!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeCopy - Copy a time-instance

! !INTERFACE:
      subroutine ESMF_TimeCopy(timeout, timein)

! !ARGUMENTS:
      type(ESMF_Time), intent(out) :: timeout
      type(ESMF_Time), intent(in) :: timein

! !DESCRIPTION:
!     Copy a time-instance to a new instance.
!
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMGn.n.n
!EOP

      timeout%basetime = timein%basetime
      timeout%YR       = timein%YR
      timeout%Calendar => timein%Calendar
!tcx      timeout%Calendar = timein%Calendar
!      write(6,*) 'tcxa ESMF_TimeCopy'
!      call flush(6)
!      write(6,*) 'tcxb ESMF_TimeCopy',timein%calendar%type%caltype
!      call flush(6)
      timeout%Calendar = ESMF_CalendarCreate(calkindflag=timein%calendar%type)

      end subroutine ESMF_TimeCopy


!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimePrint - Print out a time instant's properties


! !INTERFACE:
      subroutine ESMF_TimePrint(time, options, rc)

! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time
      character (len=*), intent(in), optional :: options
      integer, intent(out), optional :: rc
      character (len=256) :: timestr

! !DESCRIPTION:
!     To support testing/debugging, print out a {\tt ESMF\_Time}'s
!     properties.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          {\tt ESMF\_Time} instant to print out
!     \item[{[options]}]
!          Print options
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMGn.n.n
!EOP

      ! Quick hack to mimic ESMF 2.0.1
      ! Really should check value of options...
      IF ( PRESENT( options ) ) THEN
        CALL ESMF_TimeGet( time, timeString=timestr, rc=rc )
        timestr(11:11) = 'T'     ! ISO 8601 compatibility hack for debugging
        print *,' Time -----------------------------------'
        print *,' ',TRIM(timestr)
        print *,' end Time -------------------------------'
        print *
      ELSE
        call print_a_time (time)
      ENDIF

      end subroutine ESMF_TimePrint

!==============================================================================

SUBROUTINE print_a_time( time )
   IMPLICIT NONE
   type(ESMF_Time) time
   character*128 :: s
   integer rc
   CALL ESMF_TimeGet( time, timeString=s, rc=rc )
   print *,'Print a time|',TRIM(s),'|'
   write(0,*)'Print a time|',TRIM(s),'|'
   return
END SUBROUTINE print_a_time

!==============================================================================

SUBROUTINE timecmp(time1, time2, retval )
  IMPLICIT NONE
  INTEGER, INTENT(OUT) :: retval
!
! !ARGUMENTS:
  TYPE(ESMF_Time), INTENT(IN) :: time1
  TYPE(ESMF_Time), INTENT(IN) :: time2
  IF ( time1%YR .GT. time2%YR ) THEN ; retval = 1  ; RETURN ; ENDIF
  IF ( time1%YR .LT. time2%YR ) THEN ; retval = -1 ; RETURN ; ENDIF
  CALL seccmp( time1%basetime%S, time1%basetime%Sn, time1%basetime%Sd, &
               time2%basetime%S, time2%basetime%Sn, time2%basetime%Sd, &
	       retval )
END SUBROUTINE timecmp

!==============================================================================

SUBROUTINE normalize_time( time )
  ! A normalized time has time%basetime >= 0, time%basetime less than the current
  ! year expressed as a timeInterval, and time%YR can take any value
  IMPLICIT NONE
  TYPE(ESMF_Time), INTENT(INOUT) :: time
!  INTEGER(ESMF_KIND_I8) :: nsecondsinyear
  ! locals
  TYPE(ESMF_BaseTime) :: cmptime, zerotime
  INTEGER :: rc
  LOGICAL :: done

  ! first, normalize basetime
  ! this will force abs(Sn) < Sd and ensure that signs of S and Sn match

  CALL normalize_basetime( time%basetime )

  ! next, underflow negative seconds into YEARS
  ! time%basetime must end up non-negative

  zerotime%S  = 0
  zerotime%Sn = 0
  zerotime%Sd = 0
  DO WHILE ( time%basetime < zerotime )
    time%YR = time%YR - 1
    cmptime%S  = nsecondsinyear( time%YR, time%calendar%type )
    cmptime%Sn = 0
    cmptime%Sd = 0
    time%basetime = time%basetime + cmptime
  ENDDO

  ! next, overflow seconds into YEARS
  done = .FALSE.
  DO WHILE ( .NOT. done )
    cmptime%S  = nsecondsinyear( time%YR, time%calendar%type )
    cmptime%Sn = 0
    cmptime%Sd = 0
    IF ( time%basetime >= cmptime ) THEN
      time%basetime = time%basetime - cmptime
      time%YR = time%YR + 1
    ELSE
      done = .TRUE.
    ENDIF
  ENDDO

END SUBROUTINE normalize_time

!==============================================================================

SUBROUTINE timegetmonth( time, MM )
  IMPLICIT NONE
  TYPE(ESMF_Time), INTENT(IN) :: time
  INTEGER, INTENT(OUT) :: MM
  ! locals

  mm = nmonthinyearsec(time%yr,time%basetime,time%calendar%type)

END SUBROUTINE timegetmonth

!==============================================================================
SUBROUTINE timegetdayofmonth( time, DD )
  IMPLICIT NONE
  TYPE(ESMF_Time), INTENT(IN) :: time
  INTEGER, INTENT(OUT) :: DD
  ! locals

  dd = ndayinyearsec(time%yr, time%basetime, time%calendar%type)

END SUBROUTINE timegetdayofmonth

!==============================================================================

! Increment Time by number of seconds between start of year and start
! of month MM.
! 1 <= MM <= 12
! Time is NOT normalized.
SUBROUTINE timeaddmonths( time, MM, ierr )
  IMPLICIT NONE
  TYPE(ESMF_Time), INTENT(INOUT) :: time
  INTEGER, INTENT(IN) :: MM
  INTEGER, INTENT(OUT) :: ierr
  ! locals
  INTEGER(ESMF_KIND_I8) :: isec

  ierr = ESMF_SUCCESS
  IF ( ( MM < 1 ) .OR. ( MM > MONTHS_PER_YEAR ) ) THEN
    CALL wrf_message( 'ERROR timeaddmonths():  MM out of range' )
    ierr = ESMF_FAILURE
    return
  ENDIF

  isec = nsecondsinyearmonth(time%yr,MM,time%calendar%type)
  time%basetime%s = time%basetime%s + isec

END SUBROUTINE timeaddmonths

!==============================================================================

! Increment Time by number of seconds between start of year and start
! of month MM.
! 1 <= MM <= 12
! Time is NOT normalized.
SUBROUTINE ESMF_setYearWidth( yearWidthIn )

    integer, intent(in) :: yearWidthIn

    yearWidth = yearWidthIn

END SUBROUTINE ESMF_setYearWidth

!==============================================================================
!==============================================================================
end module ESMF_TimeMod
