!$$$  need to test with ESMF_ instead of WRFU_ ...  
!
! Sub-system tests for esmf_time_f90
!
! Someday, switch over to funit!  
!

MODULE my_tests
  USE module_utility
  IMPLICIT NONE

  ! Set this to .TRUE. to make wrf_error_fatal() print a message on failure 
  ! instead of stopping the program.  Use for testing only (since we cannot 
  ! catch exceptions in Fortran90!!)  
  LOGICAL :: WRF_ERROR_FATAL_PRINT = .TRUE. !FALSE.

CONTAINS

  ! Test printing of an ESMF_Time or ESMF_TimeInterval object.  
  !
  ! Correct results are also passed in through this interface and compared 
  ! with computed results.  PASS/FAIL messages are printed.  
  !
  SUBROUTINE test_print(  t_yy,  t_mm,  t_dd,  t_h,  t_m,  t_s, t_sn, t_sd, &
                         ti_yy, ti_mm, ti_dd, ti_h, ti_m, ti_s, ti_sn, ti_sd, &
                         res_str, testname, expect_error )
    INTEGER, INTENT(IN), OPTIONAL :: t_YY
    INTEGER, INTENT(IN), OPTIONAL :: t_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: t_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: t_H
    INTEGER, INTENT(IN), OPTIONAL :: t_M
    INTEGER, INTENT(IN), OPTIONAL :: t_S
    INTEGER, INTENT(IN), OPTIONAL :: t_Sn
    INTEGER, INTENT(IN), OPTIONAL :: t_Sd
    INTEGER, INTENT(IN), OPTIONAL :: ti_YY
    INTEGER, INTENT(IN), OPTIONAL :: ti_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: ti_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: ti_H
    INTEGER, INTENT(IN), OPTIONAL :: ti_M
    INTEGER, INTENT(IN), OPTIONAL :: ti_S
    INTEGER, INTENT(IN), OPTIONAL :: ti_Sn
    INTEGER, INTENT(IN), OPTIONAL :: ti_Sd
    CHARACTER (LEN=*), INTENT(IN) :: res_str
    CHARACTER (LEN=*), INTENT(IN), OPTIONAL :: testname
    LOGICAL, OPTIONAL, INTENT(IN) :: expect_error
    ! locals
    INTEGER :: it_YY
    INTEGER :: it_MM  ! month
    INTEGER :: it_DD  ! day of month
    INTEGER :: it_H
    INTEGER :: it_M
    INTEGER :: it_S
    INTEGER :: it_Sn
    INTEGER :: it_Sd
    INTEGER :: iti_YY
    INTEGER :: iti_MM  ! month
    INTEGER :: iti_DD  ! day of month
    INTEGER :: iti_H
    INTEGER :: iti_M
    INTEGER :: iti_S
    INTEGER :: iti_Sn
    INTEGER :: iti_Sd
    LOGICAL :: is_t 
    LOGICAL :: is_ti
    CHARACTER (LEN=512) :: itestname
    LOGICAL :: iexpect_error
    INTEGER rc
    TYPE(WRFU_Time)           :: t
    TYPE(WRFU_TimeInterval)   :: ti
    CHARACTER(LEN=WRFU_MAXSTR) :: str, computed_str, frac_str
    CHARACTER(LEN=17) :: type_str
    INTEGER :: res_len, computed_len
    LOGICAL :: test_passed

!  PRINT *,'DEBUG:  BEGIN test_print()'
    it_YY = 0
    it_MM = 1  ! same as Earth more simple 
    it_DD = 1  ! same as Earth more simple 
    it_H = 0
    it_M = 0
    it_S = 0
    it_Sn = 0
    it_Sd = 0
    iti_YY = 0
    iti_MM = 0
    iti_DD = 0
    iti_H = 0
    iti_M = 0
    iti_S = 0
    iti_Sn = 0
    iti_Sd = 0
    itestname = ''
    iexpect_error = .FALSE.

    IF ( PRESENT( t_YY ) ) it_YY = t_YY
    IF ( PRESENT( t_MM ) ) it_MM = t_MM
    IF ( PRESENT( t_DD ) ) it_DD = t_DD
    IF ( PRESENT( t_H ) ) it_H = t_H
    IF ( PRESENT( t_M ) ) it_M = t_M
    IF ( PRESENT( t_S ) ) it_S = t_S
    IF ( PRESENT( t_Sn ) ) it_Sn = t_Sn
    IF ( PRESENT( t_Sd ) ) it_Sd = t_Sd
    IF ( PRESENT( ti_YY ) ) iti_YY = ti_YY
    IF ( PRESENT( ti_MM ) ) iti_MM = ti_MM
    IF ( PRESENT( ti_DD ) ) iti_DD = ti_DD
    IF ( PRESENT( ti_H ) ) iti_H = ti_H
    IF ( PRESENT( ti_M ) ) iti_M = ti_M
    IF ( PRESENT( ti_S ) ) iti_S = ti_S
    IF ( PRESENT( ti_Sn ) ) iti_Sn = ti_Sn
    IF ( PRESENT( ti_Sd ) ) iti_Sd = ti_Sd
    IF ( PRESENT( testname ) ) itestname = TRIM(testname)
    IF ( PRESENT( expect_error ) ) iexpect_error = expect_error

    ! Ensure that optional arguments are consistent...
    is_t = ( PRESENT( t_YY ) .OR. PRESENT( t_MM ) .OR. &
             PRESENT( t_DD ) .OR. PRESENT( t_H ) .OR.  &
             PRESENT( t_M )  .OR. PRESENT( t_S ) .OR.  &
             PRESENT( t_Sn )  .OR. PRESENT( t_Sd ) )
    is_ti = ( PRESENT( ti_YY ) .OR. PRESENT( ti_MM ) .OR. &
              PRESENT( ti_DD ) .OR. PRESENT( ti_H ) .OR.  &
              PRESENT( ti_M )  .OR. PRESENT( ti_S ) .OR.  &
              PRESENT( ti_Sn )  .OR. PRESENT( ti_Sd ) )
    IF ( is_t .EQV. is_ti ) THEN
      CALL wrf_error_fatal( &
        'ERROR test_print:  inconsistent args' )
    ENDIF

!PRINT *,'DEBUG:  test_print():  init objects'
    ! Initialize object to be tested
    ! modify behavior of wrf_error_fatal for tests
    IF ( iexpect_error ) WRF_ERROR_FATAL_PRINT = .TRUE.
    IF ( is_t ) THEN
      type_str = 'ESMF_Time'
!PRINT *,'DEBUG:  test_print():  calling WRFU_TimeSet()'
!PRINT *,'DEBUG:  test_print():  YY,MM,DD,H,M,S,Sn,Sd = ', it_YY,it_MM,it_DD,it_H,it_M,it_S,it_Sn,it_Sd
      CALL WRFU_TimeSet( t, YY=it_YY, MM=it_MM, DD=it_DD , &
                             H=it_H, M=it_M, S=it_S, Sn=it_Sn, Sd=it_Sd, rc=rc )
!PRINT *,'DEBUG:  test_print():  back from WRFU_TimeSet()'
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeSet() ', &
                             __FILE__ , &
                             __LINE__  )
!PRINT *,'DEBUG:  test_print():  calling WRFU_TimeGet()'
      CALL WRFU_TimeGet( t, timeString=computed_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
!PRINT *,'DEBUG:  test_print():  back from WRFU_TimeGet(), computed_str = ',TRIM(computed_str)
      ! handle fractions
      IF ( t%basetime%Sd > 0 ) THEN
        IF ( t%basetime%Sn > 0 ) THEN
          WRITE(frac_str,FMT="('+',I2.2,'/',I2.2)") abs(t%basetime%Sn), t%basetime%Sd
        ELSE IF ( t%basetime%Sn < 0 ) THEN
          WRITE(frac_str,FMT="('-',I2.2,'/',I2.2)") abs(t%basetime%Sn), t%basetime%Sd
        ELSE
          frac_str = ''
        ENDIF
        computed_str = TRIM(computed_str)//TRIM(frac_str)
      ENDIF
!PRINT *,'DEBUG:  test_print():  back from WRFU_TimeGet(), computed_str = ',TRIM(computed_str)
    ELSE
      type_str = 'ESMF_TimeInterval'
!PRINT *,'DEBUG:  test_print():  calling WRFU_TimeIntervalSet()'
      CALL WRFU_TimeIntervalSet( ti, YY=iti_YY, MM=iti_MM, &
                                      D=iti_DD ,           &
                                      H=iti_H, M=iti_M,    &
                                      S=iti_S, Sn=iti_Sn, Sd=iti_Sd, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeIntervalSet() ', &
                             __FILE__ , &
                             __LINE__  )
!PRINT *,'DEBUG:  test_print():  calling WRFU_TimeIntervalGet()'
      CALL WRFU_TimeIntervalGet( ti, timeString=computed_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      ! handle fractions
      IF ( ti%basetime%Sd > 0 ) THEN
        IF ( ti%basetime%Sn > 0 ) THEN
          WRITE(frac_str,FMT="('+',I2.2,'/',I2.2)") abs(ti%basetime%Sn), ti%basetime%Sd
        ELSE IF ( ti%basetime%Sn < 0 ) THEN
          WRITE(frac_str,FMT="('-',I2.2,'/',I2.2)") abs(ti%basetime%Sn), ti%basetime%Sd
        ELSE
          frac_str = ''
        ENDIF
        computed_str = TRIM(computed_str)//TRIM(frac_str)
      ENDIF
    ENDIF
    ! restore default behavior of wrf_error_fatal
    IF ( iexpect_error ) WRF_ERROR_FATAL_PRINT = .FALSE.
!PRINT *,'DEBUG:  test_print():  done init objects'

!PRINT *,'DEBUG:  test_print():  check result'
    ! check result
    test_passed = .FALSE.
    res_len = LEN_TRIM(res_str)
    computed_len = LEN_TRIM(computed_str)
    IF ( res_len == computed_len ) THEN
      IF ( computed_str(1:computed_len) == res_str(1:res_len) ) THEN
        test_passed = .TRUE.
      ENDIF
    ENDIF
    IF ( test_passed ) THEN
      WRITE(*,FMT='(A)') 'PASS:  '//TRIM(itestname)
    ELSE
      WRITE(*,'(9A)') 'FAIL:  ',TRIM(itestname),':  printing ',TRIM(type_str), &
        '  expected <', TRIM(res_str),'>  but computed <',TRIM(computed_str),'>'
    ENDIF
!PRINT *,'DEBUG:  END test_print()'

  END SUBROUTINE test_print



  ! Test the following arithmetic operations on ESMF_Time and 
  ! ESMF_TimeInterval objects:
  !  ESMF_Time         = ESMF_Time         + ESMF_TimeInterval
  !  ESMF_Time         = ESMF_TimeInterval + ESMF_Time
  !  ESMF_Time         = ESMF_Time         - ESMF_TimeInterval
  !  ESMF_TimeInterval = ESMF_Time         - ESMF_Time        
  !  ESMF_TimeInterval = ESMF_TimeInterval + ESMF_TimeInterval
  !  ESMF_TimeInterval = ESMF_TimeInterval - ESMF_TimeInterval
  !  ESMF_TimeInterval = ESMF_TimeInterval * INTEGER
  !  ESMF_TimeInterval = ESMF_TimeInterval / INTEGER
  !
  ! Correct results are also passed in through this interface and compared 
  ! with computed results.  PASS/FAIL messages are printed.  
  !
  ! Operations are expressed as res = op1 +|- op2
  !
  SUBROUTINE test_arithmetic( add_op, multiply_op,                                       &
     op1_t_yy,  op1_t_mm,  op1_t_dd,  op1_t_h,  op1_t_m,  op1_t_s,  op1_t_sn,  op1_t_sd, &
    op1_ti_yy, op1_ti_mm, op1_ti_dd, op1_ti_h, op1_ti_m, op1_ti_s, op1_ti_sn, op1_ti_sd, &
     op2_t_yy,  op2_t_mm,  op2_t_dd,  op2_t_h,  op2_t_m,  op2_t_s,  op2_t_sn,  op2_t_sd, &
    op2_ti_yy, op2_ti_mm, op2_ti_dd, op2_ti_h, op2_ti_m, op2_ti_s, op2_ti_sn, op2_ti_sd, &
    op2_int,                                                                             &
     res_t_yy,  res_t_mm,  res_t_dd,  res_t_h,  res_t_m,  res_t_s,  res_t_sn,  res_t_sd, &
    res_ti_yy, res_ti_mm, res_ti_dd, res_ti_h, res_ti_m, res_ti_s, res_ti_sn, res_ti_sd, &
    testname, expect_error )
    LOGICAL, INTENT(IN), OPTIONAL :: add_op      ! .TRUE.=add, .FALSE.=subtract
    LOGICAL, INTENT(IN), OPTIONAL :: multiply_op ! .TRUE.=multiply, .FALSE.=divide
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_YY
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_H
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_M
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_S
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_Sn
    INTEGER, INTENT(IN), OPTIONAL :: op1_t_Sd
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_YY
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_H
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_M
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_S
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_Sn
    INTEGER, INTENT(IN), OPTIONAL :: op1_ti_Sd
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_YY
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_H
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_M
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_S
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_Sn
    INTEGER, INTENT(IN), OPTIONAL :: op2_t_Sd
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_YY
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_H
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_M
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_S
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_Sn
    INTEGER, INTENT(IN), OPTIONAL :: op2_ti_Sd
    INTEGER, INTENT(IN), OPTIONAL :: op2_int
    INTEGER, INTENT(IN), OPTIONAL :: res_t_YY
    INTEGER, INTENT(IN), OPTIONAL :: res_t_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: res_t_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: res_t_H
    INTEGER, INTENT(IN), OPTIONAL :: res_t_M
    INTEGER, INTENT(IN), OPTIONAL :: res_t_S
    INTEGER, INTENT(IN), OPTIONAL :: res_t_Sn
    INTEGER, INTENT(IN), OPTIONAL :: res_t_Sd
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_YY
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_H
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_M
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_S
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_Sn
    INTEGER, INTENT(IN), OPTIONAL :: res_ti_Sd
    CHARACTER (LEN=*), OPTIONAL, INTENT(IN) :: testname
    LOGICAL, OPTIONAL, INTENT(IN) :: expect_error
    ! locals
    LOGICAL :: iadd_op
    LOGICAL :: isubtract_op
    LOGICAL :: imultiply_op
    LOGICAL :: idivide_op
    INTEGER :: iop1_t_YY
    INTEGER :: iop1_t_MM  ! month
    INTEGER :: iop1_t_DD  ! day of month
    INTEGER :: iop1_t_H
    INTEGER :: iop1_t_M
    INTEGER :: iop1_t_S
    INTEGER :: iop1_t_Sn
    INTEGER :: iop1_t_Sd
    INTEGER :: iop1_ti_YY
    INTEGER :: iop1_ti_MM  ! month
    INTEGER :: iop1_ti_DD  ! day of month
    INTEGER :: iop1_ti_H
    INTEGER :: iop1_ti_M
    INTEGER :: iop1_ti_S
    INTEGER :: iop1_ti_Sn
    INTEGER :: iop1_ti_Sd
    INTEGER :: iop2_t_YY
    INTEGER :: iop2_t_MM  ! month
    INTEGER :: iop2_t_DD  ! day of month
    INTEGER :: iop2_t_H
    INTEGER :: iop2_t_M
    INTEGER :: iop2_t_S
    INTEGER :: iop2_t_Sn
    INTEGER :: iop2_t_Sd
    INTEGER :: iop2_ti_YY
    INTEGER :: iop2_ti_MM  ! month
    INTEGER :: iop2_ti_DD  ! day of month
    INTEGER :: iop2_ti_H
    INTEGER :: iop2_ti_M
    INTEGER :: iop2_ti_S
    INTEGER :: iop2_ti_Sn
    INTEGER :: iop2_ti_Sd
    INTEGER :: ires_t_YY
    INTEGER :: ires_t_MM  ! month
    INTEGER :: ires_t_DD  ! day of month
    INTEGER :: ires_t_H
    INTEGER :: ires_t_M
    INTEGER :: ires_t_S
    INTEGER :: ires_t_Sn
    INTEGER :: ires_t_Sd
    INTEGER :: ires_ti_YY
    INTEGER :: ires_ti_MM  ! month
    INTEGER :: ires_ti_DD  ! day of month
    INTEGER :: ires_ti_H
    INTEGER :: ires_ti_M
    INTEGER :: ires_ti_S
    INTEGER :: ires_ti_Sn
    INTEGER :: ires_ti_Sd
    LOGICAL :: op1_is_t , op2_is_t , res_is_t
    LOGICAL :: op1_is_ti, op2_is_ti, res_is_ti, op2_is_int
    INTEGER :: num_ops, num_op2
    LOGICAL :: unsupported_op, test_passed
    CHARACTER (LEN=512) :: itestname
    LOGICAL :: iexpect_error
    INTEGER rc
    TYPE(WRFU_Time)           :: op1_t , op2_t , res_t, computed_t
    TYPE(WRFU_TimeInterval)   :: op1_ti, op2_ti, res_ti, computed_ti
    CHARACTER(LEN=WRFU_MAXSTR) :: str, op1_str, op2_str, res_str, computed_str, frac_str
    CHARACTER(LEN=1) :: op_str
    CHARACTER(LEN=17) :: op1_type_str, op2_type_str, res_type_str

    iadd_op = .FALSE.
    isubtract_op = .FALSE.
    imultiply_op = .FALSE.
    idivide_op = .FALSE.
    iop1_t_YY = 0
    iop1_t_MM = 1  !see above
    iop1_t_DD = 1  !see above
    iop1_t_H = 0
    iop1_t_M = 0
    iop1_t_S = 0
    iop1_t_Sn = 0
    iop1_t_Sd = 0
    iop1_ti_YY = 0
    iop1_ti_MM = 0
    iop1_ti_DD = 0
    iop1_ti_H = 0
    iop1_ti_M = 0
    iop1_ti_S = 0
    iop1_ti_Sn = 0
    iop1_ti_Sd = 0
    iop2_t_YY = 0
    iop2_t_MM = 1  !see above
    iop2_t_DD = 1  !see above
    iop2_t_H = 0
    iop2_t_M = 0
    iop2_t_S = 0
    iop2_t_Sn = 0
    iop2_t_Sd = 0
    iop2_ti_YY = 0
    iop2_ti_MM = 0
    iop2_ti_DD = 0
    iop2_ti_H = 0
    iop2_ti_M = 0
    iop2_ti_S = 0
    iop2_ti_Sn = 0
    iop2_ti_Sd = 0
    ires_t_YY = 0
    ires_t_MM = 1  !see above
    ires_t_DD = 1  !see above
    ires_t_H = 0
    ires_t_M = 0
    ires_t_S = 0
    ires_t_Sn = 0
    ires_t_Sd = 0
    ires_ti_YY = 0
    ires_ti_MM = 0
    ires_ti_DD = 0
    ires_ti_H = 0
    ires_ti_M = 0
    ires_ti_S = 0
    ires_ti_Sn = 0
    ires_ti_Sd = 0
    itestname = ''
    iexpect_error = .FALSE.

    IF ( PRESENT( add_op ) ) THEN
      iadd_op = add_op
      isubtract_op = ( .NOT. add_op )
    ENDIF
    IF ( PRESENT( multiply_op ) ) THEN
      imultiply_op = multiply_op
      idivide_op = ( .NOT. multiply_op )
    ENDIF
    num_ops = 0
    IF ( iadd_op )      num_ops = num_ops + 1
    IF ( isubtract_op ) num_ops = num_ops + 1
    IF ( imultiply_op ) num_ops = num_ops + 1
    IF ( idivide_op )   num_ops = num_ops + 1
    IF ( num_ops /= 1 ) THEN
      CALL wrf_error_fatal( &
        'ERROR test_arithmetic:  inconsistent operation' )
    ENDIF
    IF ( PRESENT( op1_t_YY ) ) iop1_t_YY = op1_t_YY
    IF ( PRESENT( op1_t_MM ) ) iop1_t_MM = op1_t_MM
    IF ( PRESENT( op1_t_DD ) ) iop1_t_DD = op1_t_DD
    IF ( PRESENT( op1_t_H ) ) iop1_t_H = op1_t_H
    IF ( PRESENT( op1_t_M ) ) iop1_t_M = op1_t_M
    IF ( PRESENT( op1_t_S ) ) iop1_t_S = op1_t_S
    IF ( PRESENT( op1_t_Sn ) ) iop1_t_Sn = op1_t_Sn
    IF ( PRESENT( op1_t_Sd ) ) iop1_t_Sd = op1_t_Sd
    IF ( PRESENT( op1_ti_YY ) ) iop1_ti_YY = op1_ti_YY
    IF ( PRESENT( op1_ti_MM ) ) iop1_ti_MM = op1_ti_MM
    IF ( PRESENT( op1_ti_DD ) ) iop1_ti_DD = op1_ti_DD
    IF ( PRESENT( op1_ti_H ) ) iop1_ti_H = op1_ti_H
    IF ( PRESENT( op1_ti_M ) ) iop1_ti_M = op1_ti_M
    IF ( PRESENT( op1_ti_S ) ) iop1_ti_S = op1_ti_S
    IF ( PRESENT( op1_ti_Sn ) ) iop1_ti_Sn = op1_ti_Sn
    IF ( PRESENT( op1_ti_Sd ) ) iop1_ti_Sd = op1_ti_Sd
    IF ( PRESENT( op2_t_YY ) ) iop2_t_YY = op2_t_YY
    IF ( PRESENT( op2_t_MM ) ) iop2_t_MM = op2_t_MM
    IF ( PRESENT( op2_t_DD ) ) iop2_t_DD = op2_t_DD
    IF ( PRESENT( op2_t_H ) ) iop2_t_H = op2_t_H
    IF ( PRESENT( op2_t_M ) ) iop2_t_M = op2_t_M
    IF ( PRESENT( op2_t_S ) ) iop2_t_S = op2_t_S
    IF ( PRESENT( op2_t_Sn ) ) iop2_t_Sn = op2_t_Sn
    IF ( PRESENT( op2_t_Sd ) ) iop2_t_Sd = op2_t_Sd
    IF ( PRESENT( op2_ti_YY ) ) iop2_ti_YY = op2_ti_YY
    IF ( PRESENT( op2_ti_MM ) ) iop2_ti_MM = op2_ti_MM
    IF ( PRESENT( op2_ti_DD ) ) iop2_ti_DD = op2_ti_DD
    IF ( PRESENT( op2_ti_H ) ) iop2_ti_H = op2_ti_H
    IF ( PRESENT( op2_ti_M ) ) iop2_ti_M = op2_ti_M
    IF ( PRESENT( op2_ti_S ) ) iop2_ti_S = op2_ti_S
    IF ( PRESENT( op2_ti_Sn ) ) iop2_ti_Sn = op2_ti_Sn
    IF ( PRESENT( op2_ti_Sd ) ) iop2_ti_Sd = op2_ti_Sd
    IF ( PRESENT( res_t_YY ) ) ires_t_YY = res_t_YY
    IF ( PRESENT( res_t_MM ) ) ires_t_MM = res_t_MM
    IF ( PRESENT( res_t_DD ) ) ires_t_DD = res_t_DD
    IF ( PRESENT( res_t_H ) ) ires_t_H = res_t_H
    IF ( PRESENT( res_t_M ) ) ires_t_M = res_t_M
    IF ( PRESENT( res_t_S ) ) ires_t_S = res_t_S
    IF ( PRESENT( res_t_Sn ) ) ires_t_Sn = res_t_Sn
    IF ( PRESENT( res_t_Sd ) ) ires_t_Sd = res_t_Sd
    IF ( PRESENT( res_ti_YY ) ) ires_ti_YY = res_ti_YY
    IF ( PRESENT( res_ti_MM ) ) ires_ti_MM = res_ti_MM
    IF ( PRESENT( res_ti_DD ) ) ires_ti_DD = res_ti_DD
    IF ( PRESENT( res_ti_H ) ) ires_ti_H = res_ti_H
    IF ( PRESENT( res_ti_M ) ) ires_ti_M = res_ti_M
    IF ( PRESENT( res_ti_S ) ) ires_ti_S = res_ti_S
    IF ( PRESENT( res_ti_Sn ) ) ires_ti_Sn = res_ti_Sn
    IF ( PRESENT( res_ti_Sd ) ) ires_ti_Sd = res_ti_Sd
    IF ( PRESENT( testname ) ) itestname = TRIM(testname)
    IF ( PRESENT( expect_error ) ) iexpect_error = expect_error

    ! Ensure that optional arguments are consistent...
    op1_is_t = ( PRESENT( op1_t_YY ) .OR. PRESENT( op1_t_MM ) .OR. &
                 PRESENT( op1_t_DD ) .OR. PRESENT( op1_t_H ) .OR.  &
                 PRESENT( op1_t_M )  .OR. PRESENT( op1_t_S ) .OR.  &
                 PRESENT( op1_t_Sn )  .OR. PRESENT( op1_t_Sd ) )
    op1_is_ti = ( PRESENT( op1_ti_YY ) .OR. PRESENT( op1_ti_MM ) .OR. &
                  PRESENT( op1_ti_DD ) .OR. PRESENT( op1_ti_H ) .OR.  &
                  PRESENT( op1_ti_M )  .OR. PRESENT( op1_ti_S ) .OR.  &
                  PRESENT( op1_ti_Sn )  .OR. PRESENT( op1_ti_Sd ) )
    op2_is_t = ( PRESENT( op2_t_YY ) .OR. PRESENT( op2_t_MM ) .OR. &
                 PRESENT( op2_t_DD ) .OR. PRESENT( op2_t_H ) .OR.  &
                 PRESENT( op2_t_M )  .OR. PRESENT( op2_t_S ) .OR.  &
                 PRESENT( op2_t_Sn )  .OR. PRESENT( op2_t_Sd ) )
    op2_is_ti = ( PRESENT( op2_ti_YY ) .OR. PRESENT( op2_ti_MM ) .OR. &
                  PRESENT( op2_ti_DD ) .OR. PRESENT( op2_ti_H ) .OR.  &
                  PRESENT( op2_ti_M )  .OR. PRESENT( op2_ti_S ) .OR.  &
                  PRESENT( op2_ti_Sn )  .OR. PRESENT( op2_ti_Sd ) )
    op2_is_int = ( PRESENT( op2_int ) )
    res_is_t = ( PRESENT( res_t_YY ) .OR. PRESENT( res_t_MM ) .OR. &
                 PRESENT( res_t_DD ) .OR. PRESENT( res_t_H ) .OR.  &
                 PRESENT( res_t_M )  .OR. PRESENT( res_t_S ) .OR.  &
                 PRESENT( res_t_Sn )  .OR. PRESENT( res_t_Sd ) )
    res_is_ti = ( PRESENT( res_ti_YY ) .OR. PRESENT( res_ti_MM ) .OR. &
                  PRESENT( res_ti_DD ) .OR. PRESENT( res_ti_H ) .OR.  &
                  PRESENT( res_ti_M )  .OR. PRESENT( res_ti_S ) .OR.  &
                  PRESENT( res_ti_Sn )  .OR. PRESENT( res_ti_Sd ) )
    IF ( op1_is_t .EQV. op1_is_ti ) THEN
      CALL wrf_error_fatal( &
        'ERROR test_arithmetic:  inconsistent args for op1' )
    ENDIF
    num_op2 = 0
    IF ( op2_is_t   ) num_op2 = num_op2 + 1
    IF ( op2_is_ti  ) num_op2 = num_op2 + 1
    IF ( op2_is_int ) num_op2 = num_op2 + 1
    IF ( num_op2 /= 1 ) THEN
      CALL wrf_error_fatal( &
        'ERROR test_arithmetic:  inconsistent args for op2' )
    ENDIF
    IF ( res_is_t .EQV. res_is_ti ) THEN
      CALL wrf_error_fatal( &
        'ERROR test_arithmetic:  inconsistent args for result' )
    ENDIF

    ! Initialize op1
    IF ( op1_is_t ) THEN
      op1_type_str = 'ESMF_Time'
      CALL WRFU_TimeSet( op1_t, YY=iop1_t_YY, MM=iop1_t_MM, DD=iop1_t_DD , &
                                 H=iop1_t_H, M=iop1_t_M, S=iop1_t_S, Sn=iop1_t_Sn, Sd=iop1_t_Sd, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeSet() ', &
                             __FILE__ , &
                             __LINE__  )
      CALL WRFU_TimeGet( op1_t, timeString=op1_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      ! handle fractions
      CALL fraction_to_stringi8( op1_t%basetime%Sn, &
                                 op1_t%basetime%Sd, frac_str )
      op1_str = TRIM(op1_str)//TRIM(frac_str)
    ELSE
      op1_type_str = 'ESMF_TimeInterval'
      CALL WRFU_TimeIntervalSet( op1_ti, YY=iop1_ti_YY, MM=iop1_ti_MM, &
                                          D=iop1_ti_DD ,               &
                                          H=iop1_ti_H, M=iop1_ti_M,    &
                                          S=iop1_ti_S, Sn=iop1_ti_Sn, Sd=iop1_ti_Sd, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeIntervalSet() ', &
                             __FILE__ , &
                             __LINE__  )
      CALL WRFU_TimeIntervalGet( op1_ti, timeString=op1_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      ! handle fractions
      CALL fraction_to_stringi8( op1_ti%basetime%Sn, &
                                 op1_ti%basetime%Sd, frac_str )
      op1_str = TRIM(op1_str)//TRIM(frac_str)
    ENDIF
    ! Initialize op2
    IF ( op2_is_t ) THEN
      op2_type_str = 'ESMF_Time'
      CALL WRFU_TimeSet( op2_t, YY=iop2_t_YY, MM=iop2_t_MM, DD=iop2_t_DD , &
                                 H=iop2_t_H, M=iop2_t_M, S=iop2_t_S, Sn=iop2_t_Sn, Sd=iop2_t_Sd, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeSet() ', &
                             __FILE__ , &
                             __LINE__  )
      CALL WRFU_TimeGet( op2_t, timeString=op2_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      ! handle fractions
      CALL fraction_to_stringi8( op2_t%basetime%Sn, &
                                 op2_t%basetime%Sd, frac_str )
      op2_str = TRIM(op2_str)//TRIM(frac_str)
    ELSE IF ( op2_is_ti ) THEN
      op2_type_str = 'ESMF_TimeInterval'
      CALL WRFU_TimeIntervalSet( op2_ti, YY=iop2_ti_YY, MM=iop2_ti_MM, &
                                          D=iop2_ti_DD ,               &
                                          H=iop2_ti_H, M=iop2_ti_M,    &
                                          S=iop2_ti_S, Sn=iop2_ti_Sn, Sd=iop2_ti_Sd, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeIntervalSet() ', &
                             __FILE__ , &
                             __LINE__  )
      CALL WRFU_TimeIntervalGet( op2_ti, timeString=op2_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      ! handle fractions
      CALL fraction_to_stringi8( op2_ti%basetime%Sn, &
                                 op2_ti%basetime%Sd, frac_str )
      op2_str = TRIM(op2_str)//TRIM(frac_str)
    ELSE
      op2_type_str = 'INTEGER'
      IF ( op2_int > 0 ) THEN
        WRITE(op2_type_str,FMT="('+',I8.8)") ABS(op2_int)
      ELSE
        WRITE(op2_type_str,FMT="('-',I8.8)") ABS(op2_int)
      ENDIF
    ENDIF
    ! Initialize res
    IF ( res_is_t ) THEN
      res_type_str = 'ESMF_Time'
      CALL WRFU_TimeSet( res_t, YY=ires_t_YY, MM=ires_t_MM, DD=ires_t_DD , &
                                 H=ires_t_H, M=ires_t_M, S=ires_t_S, Sn=ires_t_Sn, Sd=ires_t_Sd, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeSet() ', &
                             __FILE__ , &
                             __LINE__  )
      CALL WRFU_TimeGet( res_t, timeString=res_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      ! handle fractions
      CALL fraction_to_stringi8( res_t%basetime%Sn, &
                                 res_t%basetime%Sd, frac_str )
      res_str = TRIM(res_str)//TRIM(frac_str)
    ELSE
      res_type_str = 'ESMF_TimeInterval'
      CALL WRFU_TimeIntervalSet( res_ti, YY=ires_ti_YY, MM=ires_ti_MM, &
                                          D=ires_ti_DD ,               &
                                          H=ires_ti_H, M=ires_ti_M,    &
                                          S=ires_ti_S, Sn=ires_ti_Sn, Sd=ires_ti_Sd, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                             TRIM(itestname)//'WRFU_TimeIntervalSet() ', &
                             __FILE__ , &
                             __LINE__  )
      CALL WRFU_TimeIntervalGet( res_ti, timeString=res_str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      ! handle fractions
      CALL fraction_to_stringi8( res_ti%basetime%Sn, &
                                 res_ti%basetime%Sd, frac_str )
      res_str = TRIM(res_str)//TRIM(frac_str)
    ENDIF

    ! perform requested operation
    unsupported_op = .FALSE.
    ! modify behavior of wrf_error_fatal for operator being tested
    IF ( iexpect_error ) WRF_ERROR_FATAL_PRINT = .TRUE.
    ! add
    IF ( iadd_op ) THEN
      op_str = '+'
      IF ( res_is_t ) THEN  ! result is ESMF_Time
        IF ( op1_is_t .AND. op2_is_ti ) THEN
          !  ESMF_Time         = ESMF_Time         + ESMF_TimeInterval
          computed_t = op1_t + op2_ti
        ELSE IF ( op1_is_ti .AND. op2_is_t ) THEN
          !  ESMF_Time         = ESMF_TimeInterval + ESMF_Time
          computed_t = op1_ti + op2_t
        ELSE
          unsupported_op = .TRUE.
        ENDIF
      ELSE  ! result is ESMF_TimeInterval
        IF ( op1_is_ti .AND. op2_is_ti ) THEN
          !  ESMF_TimeInterval = ESMF_TimeInterval + ESMF_TimeInterval
          computed_ti = op1_ti + op2_ti
        ELSE
          unsupported_op = .TRUE.
        ENDIF
      ENDIF
    ! subtract
    ELSE  IF ( isubtract_op ) THEN
      op_str = '-'
      IF ( res_is_t ) THEN  ! result is ESMF_Time
        IF ( op1_is_t .AND. op2_is_ti ) THEN
          !  ESMF_Time         = ESMF_Time         - ESMF_TimeInterval
          computed_t = op1_t - op2_ti
        ELSE
          unsupported_op = .TRUE.
        ENDIF
      ELSE  ! result is ESMF_TimeInterval
        IF ( op1_is_t .AND. op2_is_t ) THEN
          !  ESMF_TimeInterval = ESMF_Time         - ESMF_Time        
          computed_ti = op1_t - op2_t
        ELSE IF ( op1_is_ti .AND. op2_is_ti ) THEN
          !  ESMF_TimeInterval = ESMF_TimeInterval - ESMF_TimeInterval
          computed_ti = op1_ti - op2_ti
        ELSE
          unsupported_op = .TRUE.
        ENDIF
      ENDIF
    ELSE  IF ( imultiply_op ) THEN
      op_str = '*'
      IF ( res_is_ti ) THEN  ! result is ESMF_TimeInterval
        IF ( op1_is_ti .AND. op2_is_int ) THEN
          !  ESMF_TimeInterval = ESMF_TimeInterval * INTEGER
          computed_ti = op1_ti * op2_int
        ELSE
          unsupported_op = .TRUE.
        ENDIF
      ENDIF
    ELSE  IF ( idivide_op ) THEN
      op_str = '/'
      IF ( res_is_ti ) THEN  ! result is ESMF_TimeInterval
        IF ( op1_is_ti .AND. op2_is_int ) THEN
          !  ESMF_TimeInterval = ESMF_TimeInterval / INTEGER
          computed_ti = op1_ti / op2_int
        ELSE
          unsupported_op = .TRUE.
        ENDIF
      ENDIF
    ENDIF
    ! restore default behavior of wrf_error_fatal
    IF ( iexpect_error ) WRF_ERROR_FATAL_PRINT = .FALSE.
    IF ( unsupported_op ) THEN
      WRITE(str,*) 'ERROR test_arithmetic ',TRIM(itestname), &
        ':  unsupported operation (',                           &
        TRIM(res_type_str),' = ',TRIM(op1_type_str),' ',TRIM(op_str),' ', &
        TRIM(op2_type_str),')'
      CALL wrf_error_fatal( str )
    ENDIF

    ! check result
    test_passed = .FALSE.
    IF ( res_is_t ) THEN  ! result is ESMF_Time
      IF ( computed_t == res_t ) THEN
        test_passed = .TRUE.
      ELSE
        CALL WRFU_TimeGet( computed_t, timeString=computed_str, rc=rc )
        CALL test_check_error( WRFU_SUCCESS, rc, &
                              TRIM(itestname)//'WRFU_TimeGet() ', &
                              __FILE__ , &
                              __LINE__  )
        ! handle fractions
        CALL fraction_to_stringi8( computed_t%basetime%Sn, &
                                   computed_t%basetime%Sd, frac_str )
        computed_str = TRIM(computed_str)//TRIM(frac_str)
      ENDIF
    ELSE  ! result is ESMF_TimeInterval
      IF ( computed_ti == res_ti ) THEN
        test_passed = .TRUE.
      ELSE
        CALL WRFU_TimeIntervalGet( computed_ti, timeString=computed_str, rc=rc )
        CALL test_check_error( WRFU_SUCCESS, rc, &
                              TRIM(itestname)//'WRFU_TimeGet() ', &
                              __FILE__ , &
                              __LINE__  )
        ! handle fractions
        CALL fraction_to_stringi8( computed_ti%basetime%Sn, &
                                   computed_ti%basetime%Sd, frac_str )
        computed_str = TRIM(computed_str)//TRIM(frac_str)
      ENDIF
    ENDIF
    IF ( test_passed ) THEN
      WRITE(*,FMT='(A)') 'PASS:  '//TRIM(itestname)
    ELSE
      WRITE(*,*) 'FAIL:  ',TRIM(itestname),':  (',                        &
        TRIM(res_type_str),' = ',TRIM(op1_type_str),' ',TRIM(op_str),' ', &
        TRIM(op2_type_str),')  expected ',                                &
        TRIM(res_str),' = ',TRIM(op1_str),' ',TRIM(op_str),' ',           &
        TRIM(op2_str),'  but computed ',TRIM(computed_str)
    ENDIF

  END SUBROUTINE test_arithmetic



  ! Test adjust_io_timestr 
  SUBROUTINE test_adjust_io_timestr( TI_h, TI_m, TI_s, &
    CT_yy,  CT_mm,  CT_dd,  CT_h,  CT_m,  CT_s,        &
    ST_yy,  ST_mm,  ST_dd,  ST_h,  ST_m,  ST_s,        &
    res_str, testname )
    INTEGER, INTENT(IN) :: TI_H
    INTEGER, INTENT(IN) :: TI_M
    INTEGER, INTENT(IN) :: TI_S
    INTEGER, INTENT(IN) :: CT_YY
    INTEGER, INTENT(IN) :: CT_MM  ! month
    INTEGER, INTENT(IN) :: CT_DD  ! day of month
    INTEGER, INTENT(IN) :: CT_H
    INTEGER, INTENT(IN) :: CT_M
    INTEGER, INTENT(IN) :: CT_S
    INTEGER, INTENT(IN) :: ST_YY
    INTEGER, INTENT(IN) :: ST_MM  ! month
    INTEGER, INTENT(IN) :: ST_DD  ! day of month
    INTEGER, INTENT(IN) :: ST_H
    INTEGER, INTENT(IN) :: ST_M
    INTEGER, INTENT(IN) :: ST_S
    CHARACTER (LEN=*), INTENT(IN) :: res_str
    CHARACTER (LEN=*), INTENT(IN) :: testname
    ! locals
    TYPE(WRFU_TimeInterval) :: TI
    TYPE(WRFU_Time) :: CT, ST
    LOGICAL :: test_passed
    INTEGER :: rc
    CHARACTER(LEN=WRFU_MAXSTR) :: TI_str, CT_str, ST_str, computed_str
    ! TI
    CALL WRFU_TimeIntervalSet( TI, H=TI_H, M=TI_M, S=TI_S, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                           TRIM(testname)//'WRFU_TimeIntervalSet() ', &
                           __FILE__ , &
                           __LINE__  )
    CALL WRFU_TimeIntervalGet( TI, timeString=TI_str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(testname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )
    ! CT
    CALL WRFU_TimeSet( CT, YY=CT_YY, MM=CT_MM, DD=CT_DD , &
                            H=CT_H,   M=CT_M,   S=CT_S, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                           TRIM(testname)//'WRFU_TimeSet() ', &
                           __FILE__ , &
                           __LINE__  )
    CALL WRFU_TimeGet( CT, timeString=CT_str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(testname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )
    ! ST
    CALL WRFU_TimeSet( ST, YY=ST_YY, MM=ST_MM, DD=ST_DD , &
                            H=ST_H,   M=ST_M,   S=ST_S, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                           TRIM(testname)//'WRFU_TimeSet() ', &
                           __FILE__ , &
                           __LINE__  )
    CALL WRFU_TimeGet( ST, timeString=ST_str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(testname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )

    ! Test
    CALL adjust_io_timestr ( TI, CT, ST, computed_str )

    ! check result
    test_passed = .FALSE.
    IF ( LEN_TRIM(res_str) == LEN_TRIM(computed_str) ) THEN
      IF ( res_str(1:LEN_TRIM(res_str)) == computed_str(1:LEN_TRIM(computed_str)) ) THEN
        test_passed = .TRUE.
      ENDIF
    ENDIF

    ! print result
    IF ( test_passed ) THEN
      WRITE(*,FMT='(A)') 'PASS:  '//TRIM(testname)
    ELSE
      WRITE(*,*) 'FAIL:  ',TRIM(testname),':  adjust_io_timestr(',    &
        TRIM(TI_str),',',TRIM(CT_str),',',TRIM(ST_str),')  expected <', &
        TRIM(res_str),'>  but computed <',TRIM(computed_str),'>'
    ENDIF

  END SUBROUTINE test_adjust_io_timestr



  ! simple clock creation and advance with add-subtract tests thrown in
  ! no self checks (yet)
  SUBROUTINE test_clock_advance(                                              &
    start_yy, start_mm, start_dd, start_h, start_m, start_s,                  &
     stop_yy,  stop_mm,  stop_dd,  stop_h,  stop_m,  stop_s,                  &
    timestep_d, timestep_h, timestep_m, timestep_s, timestep_sn, timestep_sd, &
    testname, increment_S, increment_Sn, increment_Sd )
    INTEGER, INTENT(IN), OPTIONAL :: start_YY
    INTEGER, INTENT(IN), OPTIONAL :: start_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: start_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: start_H
    INTEGER, INTENT(IN), OPTIONAL :: start_M
    INTEGER, INTENT(IN), OPTIONAL :: start_S
    INTEGER, INTENT(IN), OPTIONAL :: stop_YY
    INTEGER, INTENT(IN), OPTIONAL :: stop_MM  ! month
    INTEGER, INTENT(IN), OPTIONAL :: stop_DD  ! day of month
    INTEGER, INTENT(IN), OPTIONAL :: stop_H
    INTEGER, INTENT(IN), OPTIONAL :: stop_M
    INTEGER, INTENT(IN), OPTIONAL :: stop_S
    INTEGER, INTENT(IN), OPTIONAL :: timestep_D  ! day
    INTEGER, INTENT(IN), OPTIONAL :: timestep_H
    INTEGER, INTENT(IN), OPTIONAL :: timestep_M
    INTEGER, INTENT(IN), OPTIONAL :: timestep_S
    INTEGER, INTENT(IN), OPTIONAL :: timestep_Sn
    INTEGER, INTENT(IN), OPTIONAL :: timestep_Sd
    CHARACTER (LEN=*), OPTIONAL, INTENT(IN) :: testname
    INTEGER, INTENT(IN), OPTIONAL :: increment_S  ! add and subtract this 
    INTEGER, INTENT(IN), OPTIONAL :: increment_Sn ! value each time step
    INTEGER, INTENT(IN), OPTIONAL :: increment_Sd

    ! locals
    INTEGER :: istart_YY
    INTEGER :: istart_MM  ! month
    INTEGER :: istart_DD  ! day of month
    INTEGER :: istart_H
    INTEGER :: istart_M
    INTEGER :: istart_S
    INTEGER :: istop_YY
    INTEGER :: istop_MM  ! month
    INTEGER :: istop_DD  ! day of month
    INTEGER :: istop_H
    INTEGER :: istop_M
    INTEGER :: istop_S
    INTEGER :: itimestep_D  ! day
    INTEGER :: itimestep_H
    INTEGER :: itimestep_M
    INTEGER :: itimestep_S
    INTEGER :: itimestep_Sn
    INTEGER :: itimestep_Sd
    CHARACTER (LEN=512) :: itestname, itestfullname
    INTEGER :: iincrement_S
    INTEGER :: iincrement_Sn
    INTEGER :: iincrement_Sd
    INTEGER rc
    TYPE(WRFU_Time)           :: start_time, stop_time, current_time
    TYPE(WRFU_Clock), POINTER :: domain_clock
    TYPE(WRFU_TimeInterval)   :: timestep, increment
    TYPE(WRFU_Time)           :: add_time, subtract_time
    INTEGER :: itimestep
    CHARACTER(LEN=WRFU_MAXSTR) :: str, frac_str

    istart_YY = 0
    istart_MM = 1  !see above
    istart_DD = 1  !see above
    istart_H = 0
    istart_M = 0
    istart_S = 0
    istop_YY = 0
    istop_MM = 1  !see above
    istop_DD = 1  !see above
    istop_H = 0
    istop_M = 0
    istop_S = 0
    itimestep_D = 0
    itimestep_H = 0
    itimestep_M = 0
    itimestep_S = 0
    itimestep_Sn = 0
    itimestep_Sd = 0
    itestname = ''
    iincrement_S = 0
    iincrement_Sn = 0
    iincrement_Sd = 0

    IF ( PRESENT( start_YY ) ) istart_YY = start_YY
    IF ( PRESENT( start_MM ) ) istart_MM = start_MM
    IF ( PRESENT( start_DD ) ) istart_DD = start_DD
    IF ( PRESENT( start_H ) ) istart_H = start_H
    IF ( PRESENT( start_M ) ) istart_M = start_M
    IF ( PRESENT( start_S ) ) istart_S = start_S
    IF ( PRESENT( stop_YY ) ) istop_YY = stop_YY
    IF ( PRESENT( stop_MM ) ) istop_MM = stop_MM
    IF ( PRESENT( stop_DD ) ) istop_DD = stop_DD
    IF ( PRESENT( stop_H ) ) istop_H = stop_H
    IF ( PRESENT( stop_M ) ) istop_M = stop_M
    IF ( PRESENT( stop_S ) ) istop_S = stop_S
    IF ( PRESENT( timestep_D ) ) itimestep_D = timestep_D
    IF ( PRESENT( timestep_H ) ) itimestep_H = timestep_H
    IF ( PRESENT( timestep_M ) ) itimestep_M = timestep_M
    IF ( PRESENT( timestep_S ) ) itimestep_S = timestep_S
    IF ( PRESENT( timestep_Sn ) ) itimestep_Sn = timestep_Sn
    IF ( PRESENT( timestep_Sd ) ) itimestep_Sd = timestep_Sd
    IF ( PRESENT( testname ) ) itestname = TRIM(testname)//'_'
    IF ( PRESENT( increment_S ) ) iincrement_S = increment_S
    IF ( PRESENT( increment_Sn ) ) iincrement_Sn = increment_Sn
    IF ( PRESENT( increment_Sd ) ) iincrement_Sd = increment_Sd

    ! Initialize start time, stop time, time step, clock for simple case. 
    itestfullname = TRIM(itestname)//'SETUP'
    CALL WRFU_TimeSet( start_time, YY=istart_YY, MM=istart_MM, DD=istart_DD , &
                                   H=istart_H, M=istart_M, S=istart_S, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeSet() ', &
                          __FILE__ , &
                          __LINE__  )

    CALL WRFU_TimeGet( start_time, timeString=str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )
    WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  start_time = <',TRIM(str),'>'

    CALL WRFU_TimeSet( stop_time, YY=istop_YY, MM=istop_MM, DD=istop_DD , &
                                   H=istop_H, M=istop_M, S=istop_S, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeSet() ', &
                          __FILE__ , &
                          __LINE__  )

    CALL WRFU_TimeGet( stop_time, timeString=str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )
    WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  stop_time = <',TRIM(str),'>'

    CALL WRFU_TimeIntervalSet( timestep, D=itimestep_D, H=itimestep_H, &
                                         M=itimestep_M, S=itimestep_S, &
                                         Sn=itimestep_Sn, Sd=itimestep_Sd, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeIntervalSet() ', &
                          __FILE__ , &
                          __LINE__  )

    CALL WRFU_TimeIntervalGet( timestep, timeString=str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeIntervalGet() ', &
                          __FILE__ , &
                          __LINE__  )
    ! handle fractions
    CALL fraction_to_stringi8( timestep%basetime%Sn, &
                               timestep%basetime%Sd, frac_str )
    str = TRIM(str)//TRIM(frac_str)
    WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  timestep = <',TRIM(str),'>'

    CALL WRFU_TimeIntervalSet( increment, S=iincrement_S, &
                               Sn=iincrement_Sn, Sd=iincrement_Sd, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeIntervalSet() ', &
                          __FILE__ , &
                          __LINE__  )

    CALL WRFU_TimeIntervalGet( increment, timeString=str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeIntervalGet() ', &
                          __FILE__ , &
                          __LINE__  )
    ! handle fractions
    CALL fraction_to_stringi8( increment%basetime%Sn, &
                               increment%basetime%Sd, frac_str )
    str = TRIM(str)//TRIM(frac_str)
    WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  increment = <',TRIM(str),'>'

    ALLOCATE( domain_clock )
    domain_clock = WRFU_ClockCreate( TimeStep= timestep,  &
                                     StartTime=start_time, &
                                     StopTime= stop_time,  &
                                     rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_ClockCreate() ', &
                          __FILE__ , &
                          __LINE__  )

    CALL WRFU_ClockGet( domain_clock, CurrTime=current_time, &
                        rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_ClockGet() ', &
                          __FILE__ , &
                          __LINE__  )

    CALL WRFU_TimeGet( current_time, timeString=str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )
    CALL fraction_to_stringi8( current_time%basetime%Sn, &
                               current_time%basetime%Sd, frac_str )
    str = TRIM(str)//TRIM(frac_str)
    WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  clock current_time = <',TRIM(str),'>'

    subtract_time = current_time - increment
    CALL WRFU_TimeGet( subtract_time, timeString=str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )
    CALL fraction_to_stringi8( subtract_time%basetime%Sn, &
                               subtract_time%basetime%Sd, frac_str )
    str = TRIM(str)//TRIM(frac_str)
    WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  current_time-increment = <',TRIM(str),'>'

    add_time = current_time + increment
    CALL WRFU_TimeGet( add_time, timeString=str, rc=rc )
    CALL test_check_error( WRFU_SUCCESS, rc, &
                          TRIM(itestfullname)//'WRFU_TimeGet() ', &
                          __FILE__ , &
                          __LINE__  )
    CALL fraction_to_stringi8( add_time%basetime%Sn, &
                               add_time%basetime%Sd, frac_str )
    str = TRIM(str)//TRIM(frac_str)
    WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  current_time+increment = <',TRIM(str),'>'

    ! Advance clock.  
    itestfullname = TRIM(itestname)//'ADVANCE'
    itimestep = 0
    DO WHILE ( .NOT. WRFU_ClockIsStopTime(domain_clock ,rc=rc) )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestfullname)//'WRFU_ClockIsStopTime() ', &
                            __FILE__ , &
                            __LINE__  )
      itimestep = itimestep + 1

      CALL WRFU_ClockAdvance( domain_clock, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestfullname)//'WRFU_ClockAdvance() ', &
                            __FILE__ , &
                            __LINE__  )

      CALL WRFU_ClockGet( domain_clock, CurrTime=current_time, &
                          rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestfullname)//'WRFU_ClockGet() ', &
                            __FILE__ , &
                            __LINE__  )

      CALL WRFU_TimeGet( current_time, timeString=str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestfullname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      CALL fraction_to_stringi8( current_time%basetime%Sn, &
                                 current_time%basetime%Sd, frac_str )
      str = TRIM(str)//TRIM(frac_str)
      WRITE(*,FMT='(A,A,I6.6,A,A,A)') TRIM(itestfullname),':  count = ', &
        itimestep,'  current_time = <',TRIM(str),'>'

      subtract_time = current_time - increment
      CALL WRFU_TimeGet( subtract_time, timeString=str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestfullname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      CALL fraction_to_stringi8( subtract_time%basetime%Sn, &
                                 subtract_time%basetime%Sd, frac_str )
      str = TRIM(str)//TRIM(frac_str)
      WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  current_time-increment = <',TRIM(str),'>'

      add_time = current_time + increment
      CALL WRFU_TimeGet( add_time, timeString=str, rc=rc )
      CALL test_check_error( WRFU_SUCCESS, rc, &
                            TRIM(itestfullname)//'WRFU_TimeGet() ', &
                            __FILE__ , &
                            __LINE__  )
      CALL fraction_to_stringi8( add_time%basetime%Sn, &
                                 add_time%basetime%Sd, frac_str )
      str = TRIM(str)//TRIM(frac_str)
      WRITE(*,FMT='(A,A,A,A)') TRIM(itestfullname),':  current_time+increment = <',TRIM(str),'>'

    ENDDO

    DEALLOCATE( domain_clock )
  
  END SUBROUTINE test_clock_advance

END MODULE my_tests


#if defined( ESMF_TIME_F90_ONLY ) 

! TBH:  Improve the build of Test1.exe to use WRF versions of these 
! TBH:  routines and remove these hacked-in duplicates!!  

SUBROUTINE wrf_abort
  IMPLICIT NONE
#if defined( DM_PARALLEL ) && ! defined( STUBMPI )
  INCLUDE 'mpif.h'
  INTEGER ierr
  CALL mpi_abort(MPI_COMM_WORLD,1,ierr)
#else
  STOP
#endif
END SUBROUTINE wrf_abort

SUBROUTINE wrf_message( str )
  IMPLICIT NONE
  CHARACTER*(*) str
#if defined( DM_PARALLEL ) && ! defined( STUBMPI)
  write(0,*) str
#endif
  print*, str
END SUBROUTINE wrf_message

! intentionally write to stderr only
SUBROUTINE wrf_message2( str )
  IMPLICIT NONE
  CHARACTER*(*) str
  write(0,*) str
END SUBROUTINE wrf_message2

SUBROUTINE wrf_error_fatal3( file_str, line, str )
  USE my_tests
  IMPLICIT NONE
  CHARACTER*(*) file_str
  INTEGER , INTENT (IN) :: line  ! only print file and line if line > 0
  CHARACTER*(*) str
  CHARACTER*256 :: line_str
  write(line_str,'(i6)') line
  ! special behavior for testing since Fortran cannot catch exceptions
 IF ( WRF_ERROR_FATAL_PRINT ) THEN
  ! just print message and continue
  CALL wrf_message( 'ERROR IN FILE:  '//TRIM(file_str)//'  LINE:  '//TRIM(line_str) )
 ELSE
  ! normal behavior
#if defined( DM_PARALLEL ) && ! defined( STUBMPI )
  CALL wrf_message( '-------------- FATAL CALLED ---------------' )
  ! only print file and line if line is positive
  IF ( line > 0 ) THEN
    CALL wrf_message( 'FATAL CALLED FROM FILE:  '//file_str//'  LINE:  '//TRIM(line_str) )
  ENDIF
  CALL wrf_message( str )
  CALL wrf_message( '-------------------------------------------' )
#else
  CALL wrf_message2( '-------------- FATAL CALLED ---------------' )
  ! only print file and line if line is positive
  IF ( line > 0 ) THEN
    CALL wrf_message( 'FATAL CALLED FROM FILE:  '//file_str//'  LINE:  '//TRIM(line_str) )
  ENDIF
  CALL wrf_message2( str )
  CALL wrf_message2( '-------------------------------------------' )
#endif
  CALL wrf_abort
 ENDIF
END SUBROUTINE wrf_error_fatal3

SUBROUTINE wrf_error_fatal( str )
  IMPLICIT NONE
  CHARACTER*(*) str
  CALL wrf_error_fatal3 ( ' ', 0, str )
END SUBROUTINE wrf_error_fatal


! Converts an WRFU_Time object into a WRF date-time string.
! The format of the WRF date-time strings is a slight variant on ISO 8601:
! ISO is "YYYY-MM-DDThh:mm:ss" while WRF is "YYYY-MM-DD_hh:mm:ss".
SUBROUTINE wrf_timetoa ( time, str )
   USE module_utility
   IMPLICIT NONE
   TYPE(WRFU_Time),   INTENT( IN) :: time
   CHARACTER (LEN=*), INTENT(OUT) :: str
   INTEGER rc
   CHARACTER (LEN=256) :: mess
   CALL WRFU_TimeGet( time, timeString=str, rc=rc )
   CALL test_check_error( WRFU_SUCCESS, rc, &
                         'WRFU_TimeGet() in wrf_timetoa() FAILED', &
                         __FILE__ , &
                         __LINE__  )
   ! change ISO 8601 'T' to WRF '_'
   str(11:11) = '_'
!   WRITE (mess,*) 'DEBUG wrf_timetoa():  returning with str = [',TRIM(str),']'
!   CALL wrf_debug ( 150 , mess )
   RETURN
END SUBROUTINE wrf_timetoa


! This is a test for the adjust_output_times capability in WRF, which is
! implemented with the adjust_io_timestr subroutine, defined in
! share/module_io_domain.F.
! 
! If the time manager (including the WRF extension
! WRFU_TimeIntervalDIVQuot, defined as WRFADDITION_TimeIntervalDIVQuot in
! ESMF_TimeInterval.F90) is working properly, it should behave as:
! 
! Given:
! 
!     CT = 2000-01-26_00:00:00   (current time)
!     ST = 2000-01-24_12:00:00   (start time)
!     TI = 00000_03:00:00        (time interval)
! 
! the resulting time string should be:
! 
!     2000-01-26_00:00:00
! 
! If CT is perturbed slightly, e.g. 2000-01-26_00:00:03, the resulting
! time string should still be 2000-01-26_00:00:00
! 
SUBROUTINE adjust_io_timestr ( TI, CT, ST, timestr )
   USE module_utility
   IMPLICIT NONE
! Args
   TYPE(WRFU_Time), INTENT(IN)            :: ST,CT    ! domain start and current time
   TYPE(WRFU_TimeInterval), INTENT(IN)    :: TI       ! interval
   CHARACTER*(*), INTENT(INOUT)           :: timestr  ! returned string
! Local
   TYPE(WRFU_Time)                        :: OT
   TYPE(WRFU_TimeInterval)                :: IOI
   INTEGER                                :: n

   IOI = CT-ST                               ! length of time since starting
   n = WRFU_TimeIntervalDIVQuot( IOI , TI )  ! number of whole time intervals
   IOI = TI * n                              ! amount of time since starting in whole time intervals
   OT = ST + IOI                             ! previous nearest time instant
   CALL wrf_timetoa( OT, timestr )           ! generate string
   RETURN
END SUBROUTINE adjust_io_timestr


#endif


! Check to see if expected value == actual value
! If not, print message and exit.
SUBROUTINE test_check_error( expected, actual, str, file_str, line )
  IMPLICIT NONE
  INTEGER , INTENT (IN) :: expected
  INTEGER , INTENT (IN) :: actual
  CHARACTER*(*) str
  CHARACTER*(*) file_str
  INTEGER , INTENT (IN) :: line
  CHARACTER (LEN=512)   :: rc_str
  CHARACTER (LEN=512)   :: str_with_rc
  IF ( expected .ne. actual ) THEN
    WRITE (rc_str,*) '  Routine returned error code = ',actual
    str_with_rc = 'FAIL:  '//TRIM(str)//TRIM(rc_str)
    CALL wrf_error_fatal3( file_str, line, str_with_rc )
  ENDIF
END SUBROUTINE test_check_error



PROGRAM time_manager_test
  USE module_utility
  USE my_tests
  IMPLICIT NONE
  INTEGER :: rc

  PRINT *,'BEGIN TEST SUITE'

  CALL WRFU_Initialize( defaultCalendar=WRFU_CAL_GREGORIAN, rc=rc )
  CALL test_check_error( WRFU_SUCCESS, rc, &
                        'WRFU_Initialize() ', &
                        __FILE__ , &
                        __LINE__  )
  PRINT *,'DEBUG:  back from WRFU_Initialize(), rc = ',rc

!  CALL test_print(  t_yy,  t_mm,  t_dd,  t_h,  t_m,  t_s, &
!                   ti_yy, ti_mm, ti_dd, ti_h, ti_m, ti_s, &
!                   res_str, testname )

  ! Print times
  ! "vanilla" tests
!  PRINT *,'DEBUG:  calling 1st test_print()'
  CALL test_print( t_yy=2025,  t_mm=03,  t_dd=23,  t_h=1,  t_m=20,  t_s=10, &
    res_str='2025-03-23_01:20:10', testname='printT_1' )
!  PRINT *,'DEBUG:  back from 1st test_print()'
  CALL test_print( t_yy=2000,  t_mm=1,  t_dd=1,  t_h=0,  t_m=0,  t_s=0, &
    res_str='2000-01-01_00:00:00', testname='printT_2' )
  CALL test_print( t_yy=2026,  t_mm=07,  t_dd=74,  t_h=23,  t_m=36,  t_s=90, &
    res_str='2026-07-74_23:36:90', testname='printT_3' )
  CALL test_print( t_yy=2026,  t_mm=07,  t_dd=75,  t_h=23,  t_m=36,  t_s=90, &
    res_str='2026-07-75_23:36:90', testname='printT_4' )
!  CALL test_print( t_yy=2004,  t_mm=12,  t_dd=30,  t_h=23,  t_m=59,  t_s=50, &
!    res_str='2004-12-30_23:59:50', testname='printT_5' )
!  CALL test_print( t_yy=2004,  t_mm=12,  t_dd=31,  t_h=23,  t_m=59,  t_s=50, &
!    res_str='2004-12-31_23:59:50', testname='printT_6' )
!!$$$  NOTE that this fails -- need to fix up output string for negative year
!!  CALL test_print( t_yy=-2004,  t_mm=12,  t_dd=31,  t_h=23,  t_m=59,  t_s=50, &
!!    res_str='-2004-12-31_23:59:50', testname='printT_6' )

!  ! these test default behavior of test harness
!  CALL test_print( t_s=0, &
!    res_str='0000-00-00_00:00:00', testname='printT_D1' )
!  CALL test_print( t_yy=0, &
!    res_str='0000-00-00_00:00:00', testname='printT_D2' )

  PRINT *,'yeah yeah yeah'


!  ! fractions
!  CALL test_print( t_yy=2001,  t_mm=12,  t_dd=3,  t_h=1,  t_m=20,  t_s=10, &
!    t_sn=1, t_sd=3, &
!    res_str='2001-12-03_01:20:10+01/03', testname='printT_F1' )
!  CALL test_print( t_yy=2001,  t_mm=12,  t_dd=3,  t_h=1,  t_m=20,  t_s=10, &
!    t_sn=4, t_sd=3, &
!    res_str='2001-12-03_01:20:11+01/03', testname='printT_F2' )
!  CALL test_print( t_yy=2001,  t_mm=12,  t_dd=3,  t_h=1,  t_m=20,  t_s=10, &
!    t_sn=12, t_sd=3, &
!    res_str='2001-12-03_01:20:14', testname='printT_F3' )
!  CALL test_print( t_yy=2001,  t_mm=12,  t_dd=3,  t_h=1,  t_m=20,  t_s=10, &
!    t_sn=-1, t_sd=3, &
!    res_str='2001-12-03_01:20:09+02/03', testname='printT_F4' )

  ! ERROR, MM out of range
!$$$here...  fix so this just prints "ERROR:  <testname>" in failure case
!$$$here...  also need "expect_fail" to reverse sense of PASS/FAIL message for 
!$$$here...  tests that should fail
!  CALL test_print( t_yy=2001,  t_mm=13,  t_dd=3,  t_h=1,  t_m=20,  t_s=10, &
!    res_str='2002-01-03_01:20:10', testname='printT_E1', expect_error=.TRUE. )

  ! Print time intervals
  ! "vanilla" tests
  CALL test_print( ti_yy=0,  ti_mm=0,  ti_dd=0,  ti_h=0,  ti_m=0,  ti_s=0, &
    res_str='0000000000_000:000:000', testname='printTI_1' )
  CALL test_print( ti_yy=0,  ti_mm=0,  ti_dd=500,  ti_h=0,  ti_m=0,  ti_s=9510, &
    res_str='0000000500_002:021:010', testname='printTI_2' )

!  ! these test default behavior of test harness
!  CALL test_print( ti_s=0, &
!    res_str='0000000000_000:000:000', testname='printTI_D1' )
!  CALL test_print( ti_yy=0, &
!    res_str='0000000000_000:000:000', testname='printTI_D2' )

!  ! these test negative values
!  CALL test_print( ti_yy=0000,  ti_mm=0,  ti_dd=-3,  ti_h=-1,  ti_m=-20,  ti_s=-10, &
!    res_str='-0000000003_001:020:010', testname='printTI_N1' )
!
!  ! these test mixed values
!  CALL test_print( ti_yy=0000,  ti_mm=0,  ti_dd=-3,  ti_h=1,  ti_m=20,  ti_s=10, &
!    res_str='-0000000002_022:039:050', testname='printTI_M1' )
!
!  ! fractions
!  CALL test_print( ti_yy=0000,  ti_mm=0,  ti_dd=3,  ti_h=1,  ti_m=20,  ti_s=10, &
!    ti_sn=1, ti_sd=3, &
!    res_str='0000000003_001:020:010+01/03', testname='printTI_F1' )
!  CALL test_print( ti_yy=0000,  ti_mm=0,  ti_dd=3,  ti_h=1,  ti_m=20,  ti_s=10, &
!    ti_sn=5, ti_sd=3, &
!    res_str='0000000003_001:020:011+02/03', testname='printTI_F2' )
!  CALL test_print( ti_yy=0000,  ti_mm=0,  ti_dd=-3,  ti_h=-1,  ti_m=-20,  ti_s=-10, &
!    ti_sn=-1, ti_sd=3, &
!    res_str='-0000000003_001:020:010-01/03', testname='printTI_F3' )
!  CALL test_print( ti_yy=0000,  ti_mm=0,  ti_dd=-3,  ti_h=-1,  ti_m=-20,  ti_s=-10, &
!    ti_sn=1, ti_sd=3, &
!    res_str='-0000000003_001:020:009-02/03', testname='printTI_F4' )
!

  ! these test non-normalized values
!  CALL test_print( ti_yy=2001,  ti_mm=1,  ti_dd=3,  ti_h=1,  ti_m=20,  ti_s=10, &
!    res_str='02001-001-003_001:020:010', testname='printTI_NN1', expect_error=.TRUE. )
!  CALL test_print( ti_yy=2001,  ti_mm=12,  ti_dd=3,  ti_h=1,  ti_m=20,  ti_s=10, &
!    res_str='02002-000-003_001:020:010', testname='printTI_NN2', expect_error=.TRUE. )
!  CALL test_print( ti_yy=2002,  ti_mm=5,  ti_dd=500,  ti_h=0,  ti_m=0,  ti_s=7270, &
!    res_str='02002-005-500_002:001:010', testname='printTI_NN3', expect_error=.TRUE. )


!  CALL test_arithmetic( add_op=,                                 &
!     op1_t_yy,  op1_t_mm,  op1_t_dd,  op1_t_h,  op1_t_m,  op1_t_s, &
!    op1_ti_yy, op1_ti_mm, op1_ti_dd, op1_ti_h, op1_ti_m, op1_ti_s, &
!     op2_t_yy,  op2_t_mm,  op2_t_dd,  op2_t_h,  op2_t_m,  op2_t_s, &
!    op2_ti_yy, op2_ti_mm, op2_ti_dd, op2_ti_h, op2_ti_m, op2_ti_s, &
!     res_t_yy,  res_t_mm,  res_t_dd,  res_t_h,  res_t_m,  res_t_s, &
!    res_ti_yy, res_ti_mm, res_ti_dd, res_ti_h, res_ti_m, res_ti_s, &
!    testname )

  ! Addition tests
  ! ESMF_Time = ESMF_Time + ESMF_TimeInterval
  CALL test_arithmetic( add_op=.TRUE.,                                             &
     op1_t_yy=2026,  op1_t_mm=03,  op1_t_dd=23,  op1_t_h=1,  op1_t_m=20,  op1_t_s=10, &
    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=3, op2_ti_m=10, op2_ti_s=10, &
     res_t_yy=2026,  res_t_mm=03,  res_t_dd=23,  res_t_h=4,  res_t_m=30,  res_t_s=20, &
    testname='AddT_T_TI1' )
  CALL test_arithmetic( add_op=.TRUE.,                                             &
     op1_t_yy=2001,  op1_t_mm=07,  op1_t_dd=75,  op1_t_h=22,  op1_t_m=30,  op1_t_s=00, &
    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
     res_t_yy=2002,  res_t_mm= 1,  res_t_dd=1,  res_t_h=3,  res_t_m=03,  res_t_s=10, &
    testname='AddT_T_TI2' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2003,  op1_t_mm=12,  op1_t_dd=31,  op1_t_h=22,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2004,  res_t_mm= 1,  res_t_dd=1,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI3' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=12,  op1_t_dd=31,  op1_t_h=22,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2005,  res_t_mm= 1,  res_t_dd=1,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI4' )
!  ! this case hung after the CCSM contribution
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=12,  op1_t_dd=30,  op1_t_h=22,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2004,  res_t_mm=12,  res_t_dd=31,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI5' )
!! NOTE:  CCSM folks need to decide what it means to add "1 month" to Feb. 29.  And all the 
!        other very similar cases.  Then, write this unit test!  
!!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!!!     op1_t_yy=2004,  op1_t_mm=12,  op1_t_dd=31,  op1_t_h=22,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   2, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!!     res_t_yy=2007,  res_t_mm= 1,  res_t_dd=1,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!!    testname='AddT_T_TI6' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=12,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=365, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2005,  res_t_mm=12,  res_t_dd=30,  res_t_h=8,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI7' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=12,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=367, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2006,  res_t_mm=01,  res_t_dd=01,  res_t_h=8,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI8' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2003,  op1_t_mm=12,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=365, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2004,  res_t_mm=12,  res_t_dd=29,  res_t_h=8,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI9' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2003,  op1_t_mm=12,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=366, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2004,  res_t_mm=12,  res_t_dd=30,  res_t_h=8,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI10' )
  CALL test_arithmetic( add_op=.TRUE.,                                             &
     op1_t_yy=2003,  op1_t_mm=03,  op1_t_dd=23,  op1_t_h=0,  op1_t_m=0,  op1_t_s=0, &
    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=675, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
     res_t_yy=2004,  res_t_mm=03,  res_t_dd=29,  res_t_h=4,  res_t_m=10,  res_t_s=10, &
    testname='AddT_T_TI11' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2003,  op1_t_mm=12,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=368, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2005,  res_t_mm=01,  res_t_dd=01,  res_t_h=8,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI12' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=03,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=365, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2005,  res_t_mm=03,  res_t_dd=30,  res_t_h=8,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI13' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=03,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=365, op2_ti_h=22, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2005,  res_t_mm=03,  res_t_dd=31,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI14' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=03,  op1_t_dd=30,  op1_t_h=4,  op1_t_m=30,  op1_t_s=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=366, op2_ti_h=22, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2005,  res_t_mm=04,  res_t_dd=01,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_T_TI15' )
!  ! ESMF_Time = ESMF_Time + ESMF_TimeInterval with fractions
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!     op1_t_yy=2004,  op1_t_mm=12,  op1_t_dd=31,  op1_t_h=22,  op1_t_m=30,  op1_t_s=00, &
!     op1_t_sn=01,  op1_t_sd=03, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!    op2_ti_sn=01, op2_ti_sd=03, &
!     res_t_yy=2005,  res_t_mm= 1,  res_t_dd=1,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!     res_t_sn=02,  res_t_sd=03, &
!    testname='AddT_T_TI_F1' )
!  ! this should fail (and does)
!!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!!     op1_t_yy=2004,  op1_t_mm=12,  op1_t_dd=31,  op1_t_h=22,  op1_t_m=30,  op1_t_s=00, &
!!     op1_t_sn=01,  op1_t_sd=03, &
!!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!!    op2_ti_sn=01, op2_ti_sd=03, &
!!     res_t_yy=2005,  res_t_mm= 1,  res_t_dd=1,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!!     res_t_sn=01,  res_t_sd=03, &
!!    testname='AddT_T_TI_F2' )
!  ! ESMF_Time = ESMF_TimeInterval + ESMF_Time
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!    op1_ti_yy=   0, op1_ti_mm= 0, op1_ti_dd=0, op1_ti_h=3, op1_ti_m=10, op1_ti_s=10, &
!     op2_t_yy=2001,  op2_t_mm=12,  op2_t_dd=3,  op2_t_h=1,  op2_t_m=20,  op2_t_s=10, &
!     res_t_yy=2001,  res_t_mm=12,  res_t_dd=3,  res_t_h=4,  res_t_m=30,  res_t_s=20, &
!    testname='AddT_TI_T1' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!    op1_ti_yy=   0, op1_ti_mm= 0, op1_ti_dd=0, op1_ti_h=4, op1_ti_m=10, op1_ti_s=10, &
!     op2_t_yy=2001,  op2_t_mm=12,  op2_t_dd=31,  op2_t_h=22,  op2_t_m=30,  op2_t_s=00, &
!     res_t_yy=2002,  res_t_mm= 1,  res_t_dd=1,  res_t_h=2,  res_t_m=40,  res_t_s=10, &
!    testname='AddT_TI_T2' )
!  ! ESMF_TimeInterval = ESMF_TimeInterval + ESMF_TimeInterval
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!    op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=3, op1_ti_h=1, op1_ti_m=20, op1_ti_s=10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=1, op2_ti_h=1, op2_ti_m=10, op2_ti_s=10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=4, res_ti_h=2, res_ti_m=30, res_ti_s=20, &
!    testname='AddTI_TI_TI1' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!    op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=-3, op1_ti_h=-1, op1_ti_m=-20, op1_ti_s=-10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=1, op2_ti_h=1, op2_ti_m=10, op2_ti_s=10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=-2, res_ti_h=0, res_ti_m=-10, res_ti_s=00, &
!    testname='AddTI_TI_TI2' )
!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!    op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=-3, op1_ti_h=-1, op1_ti_m=-20, op1_ti_s=-10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=-1, op2_ti_h=-1, op2_ti_m=-10, op2_ti_s=-10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=-4, res_ti_h=-2, res_ti_m=-30, res_ti_s=-20, &
!    testname='AddTI_TI_TI3' )
!

!  ! Subtraction tests
!  ! ESMF_Time = ESMF_Time - ESMF_TimeInterval
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2001,  op1_t_mm=12,  op1_t_dd=3,  op1_t_h=1,  op1_t_m=20,  op1_t_s=10, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=3, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2001,  res_t_mm=12,  res_t_dd=2,  res_t_h=22, res_t_m=10,  res_t_s=0,  &
!   testname='SubtractT_T_TI1' )
! CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2005,  op1_t_mm=1,   op1_t_dd=1,  op1_t_h=0,  op1_t_m=00,  op1_t_s=0,  &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=0, op2_ti_m=00, op2_ti_s=10, &
!     res_t_yy=2004,  res_t_mm=12,  res_t_dd=31, res_t_h=23, res_t_m=59,  res_t_s=50, &
!    testname='SubtractT_T_TI2' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2004,  op1_t_mm=1,   op1_t_dd=1,  op1_t_h=0,  op1_t_m=00,  op1_t_s=0,  &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=0, op2_ti_m=00, op2_ti_s=10, &
!     res_t_yy=2003,  res_t_mm=12,  res_t_dd=31, res_t_h=23, res_t_m=59,  res_t_s=50, &
!    testname='SubtractT_T_TI3' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2003,  op1_t_mm=1,   op1_t_dd=1,  op1_t_h=0,  op1_t_m=00,  op1_t_s=0,  &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=0, op2_ti_m=00, op2_ti_s=10, &
!     res_t_yy=2002,  res_t_mm=12,  res_t_dd=31, res_t_h=23, res_t_m=59,  res_t_s=50, &
!    testname='SubtractT_T_TI4' )
!  CALL test_arithmetic( add_op=.FALSE.,                                             &
!     op1_t_yy=2005,  op1_t_mm=04,  op1_t_dd=01,  op1_t_h=2,  op1_t_m=40,  op1_t_s=10, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=366, op2_ti_h=22, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2004,  res_t_mm=03,  res_t_dd=30,  res_t_h=4,  res_t_m=30,  res_t_s=00, &
!    testname='SubtractT_T_TI5' )
!  CALL test_arithmetic( add_op=.FALSE.,                                             &
!     op1_t_yy=2006,  op1_t_mm=01,  op1_t_dd=01,  op1_t_h=8,  op1_t_m=40,  op1_t_s=10, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=367, op2_ti_h=4, op2_ti_m=10, op2_ti_s=10, &
!     res_t_yy=2004,  res_t_mm=12,  res_t_dd=30,  res_t_h=4,  res_t_m=30,  res_t_s=00, &
!    testname='SubtractT_T_TI6' )
!  ! ESMF_Time = ESMF_Time - ESMF_TimeInterval with fractions
!  CALL test_arithmetic( add_op=.FALSE.,                                             &
!     op1_t_yy=2005,  op1_t_mm=01,  op1_t_dd=01,  op1_t_h=00,  op1_t_m=00,  op1_t_s=00, &
!     op1_t_sn=00,  op1_t_sd=00, &
!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=0, op2_ti_m=00, op2_ti_s=01, &
!    op2_ti_sn=01, op2_ti_sd=03, &
!     res_t_yy=2004,  res_t_mm=12,  res_t_dd=31,  res_t_h=23,  res_t_m=59,  res_t_s=58, &
!     res_t_sn=02,  res_t_sd=03, &
!    testname='SubtractT_T_TI_F1' )
!  ! ESMF_TimeInterval = ESMF_Time - ESMF_Time
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2001,  op1_t_mm=12,  op1_t_dd=3,  op1_t_h=1,  op1_t_m=20,  op1_t_s=10, &
!     op2_t_yy=2001,  op2_t_mm=12,  op2_t_dd=1,  op2_t_h=1,  op2_t_m=10,  op2_t_s=10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=2, res_ti_h=0, res_ti_m=10, res_ti_s=0,  &
!    testname='SubtractTI_T_T1' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2002,  op1_t_mm=1,   op1_t_dd=1,  op1_t_h=0,  op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2001,  op2_t_mm=12,  op2_t_dd=31, op2_t_h=23, op2_t_m=59,  op2_t_s=50, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=0, res_ti_h=0, res_ti_m=00, res_ti_s=10, &
!    testname='SubtractTI_T_T2' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2005,  op1_t_mm=1,   op1_t_dd=1,  op1_t_h=0,  op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2004,  op2_t_mm=12,  op2_t_dd=31, op2_t_h=23, op2_t_m=59,  op2_t_s=50, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=0, res_ti_h=0, res_ti_m=00, res_ti_s=10, &
!    testname='SubtractTI_T_T3' )
! CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2003,  op1_t_mm=03,  op1_t_dd=01, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2003,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=23, op2_t_m=59,  op2_t_s=50, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=0, res_ti_h=0, res_ti_m=00, res_ti_s=10, &
!    testname='SubtractTI_T_T4' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2004,  op1_t_mm=03,  op1_t_dd=01, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2004,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=23, op2_t_m=59,  op2_t_s=50, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=1, res_ti_h=0, res_ti_m=00, res_ti_s=10, &
!    testname='SubtractTI_T_T5' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2002,  op1_t_mm=02,  op1_t_dd=28, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2002,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=0, res_ti_h=0, res_ti_m=00, res_ti_s=00, &
!    testname='SubtractTI_T_T6' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2003,  op1_t_mm=02,  op1_t_dd=28, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2002,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=365, res_ti_h=0, res_ti_m=00, res_ti_s=00, &
!    testname='SubtractTI_T_T7' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2004,  op1_t_mm=02,  op1_t_dd=28, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2003,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=365, res_ti_h=0, res_ti_m=00, res_ti_s=00, &
!    testname='SubtractTI_T_T8' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2005,  op1_t_mm=02,  op1_t_dd=28, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2004,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=366, res_ti_h=0, res_ti_m=00, res_ti_s=00, &
!    testname='SubtractTI_T_T9' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2003,  op1_t_mm=03,  op1_t_dd=01, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2002,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=366, res_ti_h=0, res_ti_m=00, res_ti_s=00, &
!    testname='SubtractTI_T_T10' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2005,  op1_t_mm=03,  op1_t_dd=01, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2004,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=367, res_ti_h=0, res_ti_m=00, res_ti_s=00, &
!    testname='SubtractTI_T_T11' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2005,  op1_t_mm=03,  op1_t_dd=01, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=2004,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=23, op2_t_m=59,  op2_t_s=50, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=366, res_ti_h=0, res_ti_m=00, res_ti_s=10, &
!    testname='SubtractTI_T_T12' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=2004,  op1_t_mm=02,  op1_t_dd=28, op1_t_h=23, op1_t_m=59,  op1_t_s=50, &
!     op2_t_yy=2005,  op2_t_mm=03,  op2_t_dd=01, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=-366, res_ti_h=0, res_ti_m=00, res_ti_s=-10, &
!    testname='SubtractTI_T_T13' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!     op1_t_yy=-2002,  op1_t_mm=02,  op1_t_dd=28, op1_t_h=00, op1_t_m=00,  op1_t_s=00, &
!     op2_t_yy=-2002,  op2_t_mm=02,  op2_t_dd=28, op2_t_h=00, op2_t_m=00,  op2_t_s=00, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=0, res_ti_h=0, res_ti_m=00, res_ti_s=00, &
!    testname='SubtractTI_T_T14' )
!  ! ESMF_TimeInterval = ESMF_TimeInterval - ESMF_TimeInterval
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!    op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=3, op1_ti_h=1, op1_ti_m=20, op1_ti_s=10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=1, op2_ti_h=1, op2_ti_m=10, op2_ti_s=10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=2, res_ti_h=0, res_ti_m=10, res_ti_s=0,  &
!    testname='SubtractTI_TI_TI1' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!    op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=3, op1_ti_h=1, op1_ti_m=20, op1_ti_s=10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=-1, op2_ti_h=-1, op2_ti_m=-10, op2_ti_s=-10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=4, res_ti_h=2, res_ti_m=30, res_ti_s=20,  &
!    testname='SubtractTI_TI_TI2' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!    op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=-1, op1_ti_h=-1, op1_ti_m=-10, op1_ti_s=-10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=-3, op2_ti_h=-1, op2_ti_m=-20, op2_ti_s=-10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=2, res_ti_h=0, res_ti_m=10, res_ti_s=00,  &
!    testname='SubtractTI_TI_TI3' )
!  ! Negative result ESMF_TimeInterval = ESMF_TimeInterval - ESMF_TimeInterval
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!   op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=1, op1_ti_h=1, op1_ti_m=10, op1_ti_s=10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=3, op2_ti_h=1, op2_ti_m=20, op2_ti_s=10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=-2, res_ti_h=0, res_ti_m=-10, res_ti_s=0,  &
!    testname='SubtractTI_TI_TIN1' )
!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!    op1_ti_yy=0000, op1_ti_mm=00, op1_ti_dd=-1, op1_ti_h=-1, op1_ti_m=-10, op1_ti_s=-10, &
!    op2_ti_yy=0000, op2_ti_mm=00, op2_ti_dd=3, op2_ti_h=1, op2_ti_m=20, op2_ti_s=10, &
!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=-4, res_ti_h=-2, res_ti_m=-30, res_ti_s=-20,  &
!    testname='SubtractTI_TI_TIN2' )
!
!  ! Un-normalized ESMF_TimeInterval = ESMF_TimeInterval - ESMF_TimeInterval
!  ! this is an error
!!  CALL test_arithmetic( add_op=.FALSE.,                                            &
!!    op1_ti_yy=2001, op1_ti_mm=11, op1_ti_dd=3, op1_ti_h=1, op1_ti_m=20, op1_ti_s=10, &
!!    op2_ti_yy=2001, op2_ti_mm=11, op2_ti_dd=1, op2_ti_h=1, op2_ti_m=10, op2_ti_s=10, &
!!    res_ti_yy=0000, res_ti_mm=00, res_ti_dd=2, res_ti_h=0, res_ti_m=10, res_ti_s=0,  &
!!    testname='SubtractTI_TI_TIU1', expect_error=.TRUE. )
!
!  ! this one should FAIL, and does
!!  CALL test_arithmetic( add_op=.TRUE.,                                             &
!!     op1_t_yy=2001,  op1_t_mm=12,  op1_t_dd=3,  op1_t_h=1,  op1_t_m=20,  op1_t_s=10, &
!!    op2_ti_yy=   0, op2_ti_mm= 0, op2_ti_dd=0, op2_ti_h=3, op2_ti_m=10, op2_ti_s=10, &
!!     res_t_yy=2002,  res_t_mm=12,  res_t_dd=3,  res_t_h=4,  res_t_m=30,  res_t_s=20, &
!!    testname='AddTT1' )
!
!  ! Multiplication tests
!  ! ESMF_TimeInterval = ESMF_TimeInterval * INTEGER
!  CALL test_arithmetic( multiply_op=.TRUE.,                &
!    op1_ti_dd=3,  op1_ti_h=12,  op1_ti_m=18,  op1_ti_s=33, &
!    op2_int=2,                                             &
!    res_ti_dd=6,  res_ti_h=24, res_ti_m=37,  res_ti_s=06,  &
!    testname='MultiplyTI_TI_INT1' )
!  CALL test_arithmetic( multiply_op=.TRUE.,                &
!    op1_ti_dd=350,  op1_ti_h=23,  op1_ti_m=50,  op1_ti_s=50, &
!    op2_int=2,                                             &
!   res_ti_dd=701,  res_ti_h=23, res_ti_m=41,  res_ti_s=40,&
!    testname='MultiplyTI_TI_INT2' )
!  CALL test_arithmetic( multiply_op=.TRUE.,                &
!    op1_ti_s=01, op1_ti_sn=03, op1_ti_sd=04,               &
!    op2_int=8,                                             &
!    res_ti_s=14,                                           &
!   testname='MultiplyTI_TI_INT3' )
!
!  ! Division tests
!  ! ESMF_TimeInterval = ESMF_TimeInterval / INTEGER
!  CALL test_arithmetic( multiply_op=.FALSE.,               &
!    op1_ti_dd=3,  op1_ti_h=12,  op1_ti_m=18,  op1_ti_s=33, &
!    op2_int=3,                                             &
!    res_ti_dd=1,  res_ti_h=04, res_ti_m=06,  res_ti_s=11,  &
!    testname='DivideTI_TI_INT1' )
!  CALL test_arithmetic( multiply_op=.FALSE.,               &
!    op1_ti_dd=3,  op1_ti_h=12,  op1_ti_m=18,  op1_ti_s=33, &
!    op2_int=4,                                             &
!    res_ti_dd=0,  res_ti_h=21, res_ti_m=04,  res_ti_s=38,  &
!    res_ti_sn=1,  res_ti_sd=4,                             &
!    testname='DivideTI_TI_INT2' )
!  CALL test_arithmetic( multiply_op=.FALSE.,               &
!    op1_ti_s=01, op1_ti_sn=03, op1_ti_sd=04,               &
!    op2_int=5,                                             &
!    res_ti_s=0, res_ti_sn=7,  res_ti_sd=20,                &
!    testname='DivideTI_TI_INT3' )
!
!  ! Test adjust_io_timestr()
!!     CT = 2000-01-26_00:00:00   (current time)
!!     ST = 2000-01-24_12:00:00   (start time)
!!     TI = 00000_03:00:00        (time interval)
!! the resulting time string should be:
!!     2000-01-26_00:00:00
!  CALL test_adjust_io_timestr( TI_h=3, TI_m=0, TI_s=0,          &
!    CT_yy=2000,  CT_mm=1,  CT_dd=26,  CT_h=0,  CT_m=0,  CT_s=0, &
!    ST_yy=2000,  ST_mm=1,  ST_dd=24,  ST_h=12, ST_m=0,  ST_s=0, &
!    res_str='2000-01-26_00:00:00', testname='adjust_io_timestr_1' )
!! this should fail (and does)
!!  CALL test_adjust_io_timestr( TI_h=3, TI_m=0, TI_s=0,          &
!!    CT_yy=2000,  CT_mm=1,  CT_dd=26,  CT_h=0,  CT_m=0,  CT_s=0, &
!!    ST_yy=2000,  ST_mm=1,  ST_dd=24,  ST_h=12, ST_m=0,  ST_s=0, &
!!    res_str='2000-01-26_00:00:01', testname='adjust_io_timestr_FAIL1' )
!
!$$$here...  modify these to add self-test PASS/FAIL output
  CALL test_clock_advance(                                                    &
    start_yy=2024, start_mm=01, start_dd=99, start_h=3, start_m=0, start_s=0, &
     stop_yy=2024,  stop_mm=02,  stop_dd=02,  stop_h=8,  stop_m=0,  stop_s=0, &
    timestep_d=0, timestep_h=0, timestep_m=0, timestep_s=100,                 &
    testname="SimpleClockAdvance" )

  PRINT *,'END CLOCK ADVANCE'        

  CALL test_clock_advance(                                                    &
    start_yy=2024, start_mm=07, start_dd=74, start_h=23, start_m=00, start_s=0, &
     stop_yy=2025,  stop_mm=01,   stop_dd=07,   stop_h=9,  stop_m=0,  stop_s=0, &
    timestep_d=0, timestep_h=0, timestep_m=0, timestep_s=1850,                &
    testname="StdYearClockAdvance", increment_S=10 )
!
!  CALL test_clock_advance(                                                    &
!    start_yy=2004, start_mm=12, start_dd=29, start_h=9, start_m=0, start_s=0, &
!     stop_yy=2005,  stop_mm=1,   stop_dd=2,   stop_h=9,  stop_m=0,  stop_s=0, &
!    timestep_d=0, timestep_h=0, timestep_m=0, timestep_s=3600,                &
!    testname="LeapYearClockAdvance", increment_S=10 )
!
!  ! NRCM domain 3 case:  120 seconds / 9 
!  ! 18 timesteps through end of leap year
!  CALL test_clock_advance(                                                    &
!    start_yy=2004, start_mm=12, start_dd=31, start_h=23, start_m=58, start_s=0,&
!     stop_yy=2005,  stop_mm=1,   stop_dd=1,   stop_h=0,  stop_m=2,  stop_s=0, &
!    timestep_d=0, timestep_h=0, timestep_m=0, timestep_s=13,                  &
!    timestep_sn=1, timestep_sd=3,                                             &
!    testname="LeapYearFractionClockAdvance",                                  &
!    increment_S=1, increment_Sn=1, increment_Sd=3 )
!
  CALL WRFU_Finalize( rc=rc )
  CALL test_check_error( WRFU_SUCCESS, rc, &
                        'WRFU_Finalize() ', &
                        __FILE__ , &
                        __LINE__  )

  PRINT *,'END TEST SUITE'

END PROGRAM time_manager_test

