! $Id$
!
! Earth System Modeling Framework
! Copyright (c) 2002-2025, 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 University of Illinois-NCSA License.
!
!==============================================================================
#define ESMF_FILENAME "ESMF_Time.F90"
!==============================================================================
!
!     ESMF Time Module
      module ESMF_TimeMod
!
!==============================================================================
!
! This file contains the Time class definition and all Time class methods.
!
!------------------------------------------------------------------------------
! INCLUDES
#include "ESMF.h"
#include "ESMF_TimeMgr.inc"

!==============================================================================
!BOPI
! !MODULE: ESMF_TimeMod
!
! !DESCRIPTION:
! Part of Time Manager Fortran API wrapper of C++ implementation.
!
! Defines Fortran 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
      use ESMF_UtilTypesMod
      use ESMF_InitMacrosMod
      use ESMF_LogErrMod
      use ESMF_IOUtilMod

      ! associated derived types
      use ESMF_TimeIntervalTypeMod
      use ESMF_CalendarMod

      ! type definition for this module
      use ESMF_TimeTypeMod

      implicit none
!
!------------------------------------------------------------------------------
! !PRIVATE TYPES:
      private
!------------------------------------------------------------------------------
!     ! ESMF_Time definition in ESMF_TimeTypeMod to resolve mutual
!     ! dependency with ESMF_TimeInterval

!------------------------------------------------------------------------------
! !PUBLIC TYPES:
      public ESMF_Time
!------------------------------------------------------------------------------
!
! !PUBLIC MEMBER FUNCTIONS:

! - ESMF-public methods:
      public operator(+)
      public operator(-)
      public operator(==)
      public operator(/=)
      public operator(<)
      public operator(<=)
      public operator(>)
      public operator(>=)
      public ESMF_TimeGet
      public ESMF_TimeIsLeapYear
      public ESMF_TimeIsSameCalendar
      public ESMF_TimePrint
      public ESMF_TimeReadRestart
      public ESMF_TimeSet
      public ESMF_TimeSyncToRealTime
      public ESMF_TimeValidate
      public ESMF_TimeWriteRestart

! - ESMF-internal methods:
      public ESMF_TimeGetInit
      public ESMF_TimeInit

!EOPI

! !PRIVATE MEMBER FUNCTIONS:
      private ESMF_TimeInc
      private ESMF_TimeDec
      private ESMF_TimeDiff
      private ESMF_TimeEQ
      private ESMF_TimeNE
      private ESMF_TimeLT
      private ESMF_TimeLE
      private ESMF_TimeGT
      private ESMF_TimeGE

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

!==============================================================================
!
! INTERFACE BLOCKS
!
!==============================================================================
!BOP
! !IROUTINE:  ESMF_TimeAssignment(=) - Assign a Time to another Time
!
! !INTERFACE:
!     interface assignment(=)
!     time1 = time2
!
! !ARGUMENTS:
!     type(ESMF_Time) :: time1
!     type(ESMF_Time) :: time2
! 
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Set {\tt time1} equal to {\tt time2}.  This is the default Fortran
!     assignment, which creates a complete, independent copy of {\tt time2} 
!     as {\tt time1}.  If {\tt time2} is an invalid {\tt ESMF\_Time} object then
!     {\tt time1} will be equally invalid after the assignment.
!
!     The arguments are:
!     \begin{description} 
!     \item[time1] 
!          The {\tt ESMF\_Time} to be set.
!     \item[time2] 
!          The {\tt ESMF\_Time} to be copied.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
!     None, documentation only, to describe the behavior of the default 
!     Fortran assignment(=).
!
! !REQUIREMENTS:
!     API review 11/2010.
! 
!     end interface
! 
!------------------------------------------------------------------------------
!
!BOP
! !IROUTINE:  ESMF_TimeOperator(+) - Increment a Time by a TimeInterval
!
! !INTERFACE:
      interface operator(+)
!     time2 = time1 + timeinterval      
!
! !RETURN VALUE:   
!     type(ESMF_Time) :: time2
!
! !ARGUMENTS:
!     type(ESMF_Time),         intent(in) :: time1
!     type(ESMF_TimeInterval), intent(in) :: timeinterval
! 
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (+) operator for the {\tt ESMF\_Time} class to increment
!     {\tt time1} with {\tt timeinterval} and return the result as an
!     {\tt ESMF\_Time}.
!
!     The arguments are:
!     \begin{description} 
!     \item[time1] 
!          The {\tt ESMF\_Time} to increment.
!     \item[timeinterval] 
!          The {\tt ESMF\_TimeInterval} to add to the given {\tt ESMF\_Time}.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeInc    ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.4, TMG2.4.5, TMG5.1, TMG7.2
! 
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(-) - Decrement a Time by a TimeInterval
!
! !INTERFACE:
      interface operator(-)
!     time2 = time1 - timeinterval      
! 
! !RETURN VALUE:
!     type(ESMF_Time) :: time2
! 
! !ARGUMENTS:
!     type(ESMF_Time),         intent(in) :: time1
!     type(ESMF_TimeInterval), intent(in) :: timeinterval
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (-) operator for the {\tt ESMF\_Time} class to decrement
!     {\tt time1} with {\tt timeinterval}, and return the result as an
!     {\tt ESMF\_Time}.
! 
!     The arguments are:      
!     \begin{description}
!     \item[time1]
!          The {\tt ESMF\_Time} to decrement.
!     \item[timeinterval]
!          The {\tt ESMF\_TimeInterval} to subtract from the given
!          {\tt ESMF\_Time}.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeDec    ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.4, TMG2.4.5, TMG5.1, TMG7.2
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(-) - Return the difference between two Times
!
! !INTERFACE:
!     interface operator(-)
!     timeinterval = time1 - time2      
!
! !RETURN VALUE:
!     type(ESMF_TimeInterval) :: timeinterval
! 
! !ARGUMENTS:
!     type(ESMF_Time),         intent(in) :: time1
!     type(ESMF_Time),         intent(in) :: time2
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (-) operator for the {\tt ESMF\_Time} class to return the
!     difference between {\tt time1} and {\tt time2} as an
!     {\tt ESMF\_TimeInterval}.  It is assumed that {\tt time1} is later than
!     {\tt time2}; if not, the resulting {\tt ESMF\_TimeInterval} will have a
!     negative value.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          The first {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          The second {\tt ESMF\_Time} in comparison.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeDiff   ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.6, TMG5.2, TMG7.2
!
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(==) - Test if Time 1 is equal to Time 2
!
! !INTERFACE:
      interface operator(==)
!     if (time1 == time2) then ... endif
!                  OR
!     result = (time1 == time2)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     type(ESMF_Time), intent(in) :: time1
!     type(ESMF_Time), intent(in) :: time2
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (==) operator for the {\tt ESMF\_Time} class to return 
!     {\tt .true.} if {\tt time1} and {\tt time2} represent the same instant 
!     in time, and {\tt .false.} otherwise.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          Second {\tt ESMF\_Time} in comparison.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeEQ   ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.3, TMG7.2
!
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(/=) - Test if Time 1 is not equal to Time 2
!
! !INTERFACE:
      interface operator(/=)
!     if (time1 /= time2) then ... endif
!                  OR
!     result = (time1 /= time2)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     type(ESMF_Time), intent(in) :: time1
!     type(ESMF_Time), intent(in) :: time2
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (/=) operator for the {\tt ESMF\_Time} class to return 
!     {\tt .true.} if {\tt time1} and {\tt time2} do not represent the same 
!     instant in time, and {\tt .false.} otherwise.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          Second {\tt ESMF\_Time} in comparison.
!     \end{description}
! 
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeNE   ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.3, TMG7.2
!
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(<) - Test if Time 1 is less than Time 2
!
! !INTERFACE:
      interface operator(<)
!     if (time1 < time2) then ... endif
!                  OR
!     result = (time1 < time2)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     type(ESMF_Time), intent(in) :: time1
!     type(ESMF_Time), intent(in) :: time2
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (<) operator for the {\tt ESMF\_Time} class to return 
!     {\tt .true.} if {\tt time1} is earlier in time than {\tt time2}, and 
!     {\tt .false.} otherwise.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          Second {\tt ESMF\_Time} in comparison.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeLT   ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.3, TMG7.2
!
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(<=) - Test if Time 1 is less than or equal to Time 2
!
! !INTERFACE:
      interface operator(<=)
!     if (time1 <= time2) then ... endif
!                  OR
!     result = (time1 <= time2)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     type(ESMF_Time), intent(in) :: time1
!     type(ESMF_Time), intent(in) :: time2
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (<=) operator for the {\tt ESMF\_Time} class to return 
!     {\tt .true.} if {\tt time1} is earlier in time or the same time as 
!     {\tt time2}, and {\tt .false.} otherwise.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          Second {\tt ESMF\_Time} in comparison.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeLE   ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.3, TMG7.2
!
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(>) - Test if Time 1 is greater than Time 2
!
! !INTERFACE:
      interface operator(>)
!     if (time1 > time2) then ... endif
!                  OR
!     result = (time1 > time2)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     type(ESMF_Time), intent(in) :: time1
!     type(ESMF_Time), intent(in) :: time2
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (>) operator for the {\tt ESMF\_Time} class to return 
!     {\tt .true.} if {\tt time1} is later in time than {\tt time2}, and 
!     {\tt .false.} otherwise.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          Second {\tt ESMF\_Time} in comparison.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeGT   ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.3, TMG7.2
!
      end interface
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_TimeOperator(>=) - Test if Time 1 is greater than or equal to Time 2
!
! !INTERFACE:
      interface operator(>=)
!     if (time1 >= time2) then ... endif
!                  OR
!     result = (time1 >= time2)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     type(ESMF_Time), intent(in) :: time1
!     type(ESMF_Time), intent(in) :: time2
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Overloads the (>=) operator for the {\tt ESMF\_Time} class to return 
!     {\tt .true.} if {\tt time1} is later in time or the same time as 
!     {\tt time2}, and {\tt .false.} otherwise.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          First {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          Second {\tt ESMF\_Time} in comparison.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_TimeGE   ! internal implementation
!
! !REQUIREMENTS:
!     TMG2.4.3, TMG7.2
!
      end interface
!
!==============================================================================

  interface ESMF_TimeSet
    module procedure ESMF_TimeSetDefault
    module procedure ESMF_TimeSetString
  end interface

      contains

!==============================================================================
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeGet()"
!BOP
! !IROUTINE: ESMF_TimeGet - Get a Time value 

! !INTERFACE:
      subroutine ESMF_TimeGet(time, keywordEnforcer, &
        yy, yy_i8, &
        mm, dd, &
        d, d_i8, &
        h, m, &
        s, s_i8, &
        ms, us, ns, &
        d_r8, h_r8, m_r8, s_r8, &
        ms_r8, us_r8, ns_r8, &
        sN, sN_i8, sD, sD_i8, &
        calendar, calkindflag, timeZone, &
        timeString, timeStringISOFrac, &
        dayOfWeek, midMonth, &
        dayOfYear,  dayOfYear_r8, &
        dayOfYear_intvl, rc)

! !ARGUMENTS:
      type(ESMF_Time),         intent(in)            :: time
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer(ESMF_KIND_I4),   intent(out), optional :: yy
      integer(ESMF_KIND_I8),   intent(out), optional :: yy_i8
      integer,                 intent(out), optional :: mm
      integer,                 intent(out), optional :: dd
      integer(ESMF_KIND_I4),   intent(out), optional :: d
      integer(ESMF_KIND_I8),   intent(out), optional :: d_i8
      integer(ESMF_KIND_I4),   intent(out), optional :: h
      integer(ESMF_KIND_I4),   intent(out), optional :: m
      integer(ESMF_KIND_I4),   intent(out), optional :: s
      integer(ESMF_KIND_I8),   intent(out), optional :: s_i8
      integer(ESMF_KIND_I4),   intent(out), optional :: ms
      integer(ESMF_KIND_I4),   intent(out), optional :: us
      integer(ESMF_KIND_I4),   intent(out), optional :: ns
      real(ESMF_KIND_R8),      intent(out), optional :: d_r8
      real(ESMF_KIND_R8),      intent(out), optional :: h_r8
      real(ESMF_KIND_R8),      intent(out), optional :: m_r8
      real(ESMF_KIND_R8),      intent(out), optional :: s_r8
      real(ESMF_KIND_R8),      intent(out), optional :: ms_r8
      real(ESMF_KIND_R8),      intent(out), optional :: us_r8
      real(ESMF_KIND_R8),      intent(out), optional :: ns_r8
      integer(ESMF_KIND_I4),   intent(out), optional :: sN
      integer(ESMF_KIND_I8),   intent(out), optional :: sN_i8
      integer(ESMF_KIND_I4),   intent(out), optional :: sD
      integer(ESMF_KIND_I8),   intent(out), optional :: sD_i8
      type(ESMF_Calendar),     intent(out), optional :: calendar
      type(ESMF_CalKind_Flag), intent(out), optional :: calkindflag
      integer,                 intent(out), optional :: timeZone ! not imp
      character (len=*),       intent(out), optional :: timeString
      character (len=*),       intent(out), optional :: timeStringISOFrac
      integer,                 intent(out), optional :: dayOfWeek
      type(ESMF_Time),         intent(out), optional :: midMonth
      integer(ESMF_KIND_I4),   intent(out), optional :: dayOfYear
      real(ESMF_KIND_R8),      intent(out), optional :: dayOfYear_r8
      type(ESMF_TimeInterval), intent(out), optional :: dayOfYear_intvl
      integer,                 intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Gets the value of {\tt time} in units specified by the user
!     via Fortran optional arguments.  See {\tt ESMF\_TimeSet()} above for a
!     description of time units and calendars.
!
!     The ESMF Time Manager represents and manipulates time internally with 
!     integers to maintain precision.  Hence, user-specified floating point 
!     values are converted internally from integers.  For example, if a time
!     value is 5 and 3/8 seconds (s=5, sN=3, sD=8), and you want to get it as
!     floating point seconds, you would get 5.375 (s\_r8=5.375).
!
!     Units are bound (normalized) by the next larger unit specified.  For
!     example, if a time is defined to be 2:00 am on February 2, 2004, then
!     {\tt ESMF\_TimeGet(dd=day, h=hours, s=seconds)} would return
!       {\tt day = 2}, {\tt hours = 2}, {\tt seconds = 0},
!     whereas {\tt ESMF\_TimeGet(dd = day, s=seconds)} would return
!       {\tt day = 2}, {\tt seconds = 7200}.
!     Note that {\tt hours} and {\tt seconds} are bound by a day.  If bound
!     by a month,
!     {\tt ESMF\_TimeGet(mm=month, h=hours, s=seconds)} would return
!       {\tt month = 2}, {\tt hours = 26}, {\tt seconds = 0},
!     and {\tt ESMF\_TimeGet(mm = month, s=seconds)} would return
!       {\tt month = 2}, {\tt seconds = 93600} (26 * 3600).
!     Similarly, if bound to a year,
!     {\tt ESMF\_TimeGet(yy=year, h=hours, s=seconds)} would return
!       {\tt year = 2004}, {\tt hours = 770} (32*24 + 2), {\tt seconds = 0},
!     and {\tt ESMF\_TimeGet(yy = year, s=seconds)} would return
!       {\tt year = 2004}, {\tt seconds = 2772000} (770 * 3600).
!
!     However, double precision time units are not considered in this normalization:
!     Double precision time units are still bound by units of a day or larger, but double
!     precision time units of an hour or smaller neither bind nor are bound by other time
!     units of an hour or smaller (either integer or double precision). For example,
!     with the same time setting as above (2:00 am on February 2, 2004),
!     {\tt ESMF\_TimeGet(dd=day, h\_r8=hours\_r8, s=seconds)} would return
!       {\tt day = 2}, {\tt hours\_r8 = 2.0}, {\tt seconds = 7200}, and
!     {\tt ESMF\_TimeGet(dd=day, h=hours, s\_r8=seconds\_r8)} would return
!       {\tt day = 2}, {\tt hours = 2}, {\tt seconds\_r8 = 7200.0}.
!
!     For {\tt timeString}, {\tt timeStringISOFrac}, {\tt dayOfWeek},
!     {\tt midMonth}, {\tt dayOfYear}, {\tt dayOfYear\_intvl}, and
!     {\tt dayOfYear\_r8} described below, valid calendars are Gregorian,
!     Julian, No Leap, 360 Day and Custom calendars.  Not valid for
!     Julian Day, Modified Julian Day, or No Calendar. \\
!
!     For {\tt timeString} and {\tt timeStringISOFrac}, YYYY format returns
!     at least 4 digits; years <= 999 are padded on the left with zeroes and
!     years >= 10000 return the number of digits required.
!
!     For timeString, convert {\tt ESMF\_Time}'s value into partial ISO 8601
!     format YYYY-MM-DDThh:mm:ss[:n/d].  See ~\cite{ISO} and ~\cite{ISOnotes}.
!     See also method {\tt ESMF\_TimePrint()}.
!     
!     For timeStringISOFrac, convert {\tt ESMF\_Time}'s value into full ISO 8601
!     format YYYY-MM-DDThh:mm:ss[.f].  See ~\cite{ISO} and ~\cite{ISOnotes}.
!     See also method {\tt ESMF\_TimePrint()}.
!     
!     For dayOfWeek, gets the day of the week the given {\tt ESMF\_Time}
!     instant falls on.  ISO 8601 standard:  Monday = 1 through Sunday = 7.
!     See ~\cite{ISO} and ~\cite{ISOnotes}.
!
!     For midMonth, gets the middle time instant of the month that the given
!     {\tt ESMF\_Time} instant falls on.
!
!     For dayOfYear, gets the day of the year that the given {\tt ESMF\_Time}
!     instant falls on.  See range discussion in argument list below.
!     Return as an integer value.
!
!     For dayOfYear\_r8, gets the day of the year the given {\tt ESMF\_Time}
!     instant falls on.  See range discussion in argument list below.
!     Return as floating point value; fractional part represents the time of
!     day.
!
!     \begin{sloppypar}
!     For dayOfYear\_intvl, gets the day of the year the given {\tt ESMF\_Time}
!     instant falls on.  Return as an {\tt ESMF\_TimeInterval}.
!     \end{sloppypar}
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to query.
!     \item[{[yy]}]
!          Integer year (32-bit).
!     \item[{[yy\_i8]}]
!          Integer year (large, 64-bit).
!     \item[{[mm]}]
!          Integer month.
!     \item[{[dd]}]
!          Integer day of the month.
!     \item[{[d]}]
!          Integer Julian date, or Modified Julian date (32-bit).
!     \item[{[d\_i8]}]
!          Integer Julian date, or Modified Julian date (large, 64-bit).
!     \item[{[h]}]
!          Integer hour.
!     \item[{[m]}]
!          Integer minute.
!     \item[{[s]}]
!          Integer second (32-bit).
!     \item[{[s\_i8]}]
!          Integer second (large, 64-bit).
!     \item[{[ms]}]
!          Integer millisecond.
!     \item[{[us]}]
!          Integer microsecond.
!     \item[{[ns]}]
!          Integer nanosecond.
!     \item[{[d\_r8]}]
!          Double precision day.
!     \item[{[h\_r8]}]
!          Double precision hour.
!     \item[{[m\_r8]}]
!          Double precision minute.
!     \item[{[s\_r8]}]
!          Double precision second.
!     \item[{[ms\_r8]}]
!          Double precision millisecond.
!     \item[{[us\_r8]}]
!          Double precision microsecond.
!     \item[{[ns\_r8]}]
!          Double precision nanosecond.
!     \item[{[sN]}]
!          Integer numerator of fractional second (sN/sD).
!     \item[{[sN\_i8]}]
!          Integer numerator of fractional second (sN\_i8/sD\_i8)
!                                                           (large, <= 64-bit).
!     \item[{[sD]}]
!          Integer denominator of fractional second (sN/sD).
!     \item[{[sD\_i8]}]
!          Integer denominator of fractional second (sN\_i8/sD\_i8)
!                                                           (large, <= 64-bit).
!     \item[{[calendar]}]
!          Associated {\tt Calendar}.
!     \item[{[calkindflag]}]
!          Associated {\tt CalKind\_Flag}.
!     \item[{[timeZone]}]
!          Associated timezone (hours offset from UCT, e.g. EST = -5).
!          (Not implemented yet).
!     \item[{[timeString]}]
!          \begin{sloppypar}
!          Convert time value to format string YYYY-MM-DDThh:mm:ss[:n/d],
!          where n/d is numerator/denominator of any fractional seconds and
!          all other units are in ISO 8601 format.  See ~\cite{ISO} and
!          ~\cite{ISOnotes}.  See also method {\tt ESMF\_TimePrint()}.
!          \end{sloppypar}
!     \item[{[timeStringISOFrac]}]
!          Convert time value to strict ISO 8601 format string
!          YYYY-MM-DDThh:mm:ss[.f], where f is decimal form of any fractional
!          seconds.  See ~\cite{ISO} and ~\cite{ISOnotes}.  See also method
!          {\tt ESMF\_TimePrint()}.
!     \item[{[dayOfWeek]}]
!          The time instant's day of the week [1-7].
!     \item[{[MidMonth]}]
!          The given time instant's middle-of-the-month time instant.
!     \item[{[dayOfYear]}]
!          The {\tt ESMF\_Time} instant's integer day of the year.
!          [1-366] for Gregorian and Julian calendars, [1-365] for No-Leap
!          calendar.  [1-360] for 360-Day calendar.  User-defined range
!          for Custom calendar.
!     \item[{[dayOfYear\_r8]}]
!          The {\tt ESMF\_Time} instant's floating point day of the year.
!          [1.x-366.x] for Gregorian and Julian calendars, [1.x-365.x] for
!          No-Leap calendar.  [1.x-360.x] for 360-Day calendar.  User-defined
!          range for Custom calendar.
!     \item[{[dayOfYear\_intvl]}]
!          The {\tt ESMF\_Time} instant's day of the year as an
!          {\tt ESMF\_TimeInterval}.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
! !REQUIREMENTS:
!     TMG2.1, TMG2.5.1, TMG2.5.6

      ! temp time string for C++ to fill
      character (len=ESMF_MAXSTR) :: tempTimeString, tempTimeStringISOFrac

      ! initialize time string lengths to zero for non-existent time string
      integer :: timeStringLen, timeStringLenISOFrac
      integer :: tempTimeStringLen, tempTimeStringLenISOFrac
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,rc)

      timeStringLen = 0     
      timeStringLenISOFrac = 0     
      tempTimeStringLen = 0
      tempTimeStringLenISOFrac = 0

      ! if used, get length of given timeString for C++ validation
      if (present(timeString)) then
        timeStringLen = len(timeString)
      end if
      if (present(timeStringISOFrac)) then
        timeStringLenISOFrac = len(timeStringISOFrac)
      end if

      ! use optional args for any subset
      call c_ESMC_TimeGet(time, yy, yy_i8, mm, dd, d, d_i8, &
                          h, m, s, s_i8, ms, us, ns, &
                          d_r8, h_r8, m_r8, s_r8, ms_r8, us_r8, ns_r8, &
                          sN, sN_i8, sD, sD_i8, &
                          calendar, calkindflag, timeZone, &
                          timeStringLen, tempTimeStringLen, tempTimeString, &
                          timeStringLenISOFrac, tempTimeStringLenISOFrac, &
                          tempTimeStringISOFrac, &
                          dayOfWeek, MidMonth, dayOfYear, dayOfYear_r8, &
                          dayOfYear_intvl, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! copy temp time string back to given time string to restore
      !   native Fortran storage style
      if (present(timeString)) then
        timeString = tempTimeString(1:tempTimeStringLen)
      endif
      if (present(timeStringISOFrac)) then
        timeStringISOFrac = tempTimeStringISOFrac(1:tempTimeStringLenISOFrac)
      endif

      ! mark outputs as successfully initialized
      call ESMF_TimeInit(midMonth)
      call ESMF_TimeIntervalInit(dayOfYear_intvl)
      call ESMF_CalendarSetInitCreated(calendar)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeGet

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeIsLeapYear()"
!BOP
! !IROUTINE: ESMF_TimeIsLeapYear - Determine if a Time is in a leap year

! !INTERFACE:
      function ESMF_TimeIsLeapYear(time, keywordEnforcer, rc)

! !RETURN VALUE:
      logical :: ESMF_TimeIsLeapYear

! !ARGUMENTS:
      type(ESMF_Time), intent(in)            :: time
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,         intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Returns {\tt .true.} if given time is in a leap year, and {\tt .false.}
!     otherwise.  See also {\tt ESMF\_CalendarIsLeapYear()}.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The {\tt ESMF\_Time} to check for leap year.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
! !REQUIREMENTS:
!     TMGn.n.n
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! Initialize output value in case of error
      ESMF_TimeIsLeapYear = .false.

      ! check input
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,rc)

      ! invoke C to C++ entry point
      call c_ESMC_TimeIsLeapYear(time, ESMF_TimeIsLeapYear, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end function ESMF_TimeIsLeapYear

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeIsSameCalendar()"
!BOP
! !IROUTINE: ESMF_TimeIsSameCalendar - Compare Calendars of two Times

! !INTERFACE:
      function ESMF_TimeIsSameCalendar(time1, time2, keywordEnforcer, rc)

! !RETURN VALUE:
      logical :: ESMF_TimeIsSameCalendar

! !ARGUMENTS:
      type(ESMF_Time), intent(in)            :: time1
      type(ESMF_Time), intent(in)            :: time2
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,         intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Returns {\tt .true.} if the Calendars in these Times are
!     the same, {\tt .false.} otherwise.
!
!     The arguments are:
!     \begin{description}
!     \item[time1]
!          The first {\tt ESMF\_Time} in comparison.
!     \item[time2]
!          The second {\tt ESMF\_Time} in comparison.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
! !REQUIREMENTS:
!     TMGn.n.n
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! Initialize output value in case of error
      ESMF_TimeIsSameCalendar = .false.

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,rc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,rc)

      ! invoke C to C++ entry point
      call c_ESMC_TimeIsSameCalendar(time1, time2, ESMF_TimeIsSameCalendar, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS    
      end function ESMF_TimeIsSameCalendar

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimePrint()"
!BOP
! !IROUTINE:  ESMF_TimePrint - Print Time information

! !INTERFACE:
      subroutine ESMF_TimePrint(time, keywordEnforcer, options, preString, unit, rc)

! !ARGUMENTS:
      type(ESMF_Time),   intent(in)            :: time
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      character (len=*), intent(in),  optional :: options
      character(*),      intent(in),  optional :: preString
      character(*),      intent(out), optional :: unit
      integer,           intent(out), optional :: rc

!
! !DESCRIPTION:
!     Prints out the contents of an {\tt ESMF\_Time} to {\tt stdout}, in
!     support of testing and debugging.  The options control the type of
!     information and level of detail.  For options "string" and "string
!     isofrac", YYYY format returns at least 4 digits; years <= 999 are
!     padded on the left with zeroes and years >= 10000 return the number
!     of digits required. \\
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The {\tt ESMF\_Time} to be printed out.
!     \item[{[options]}]
!          Print options. If none specified, prints all Time property values. \\
!          "string" - prints {\tt time}'s value in ISO 8601 format for all units
!                     through seconds.  For any non-zero fractional seconds,
!                     prints in integer rational fraction form n/d.  Format is
!                     YYYY-MM-DDThh:mm:ss[:n/d], where [:n/d] is the 
!                     integer numerator and denominator of the fractional
!                     seconds value, if present.  See ~\cite{ISO} and
!                     ~\cite{ISOnotes}.  See also method
!                     {\tt ESMF\_TimeGet(..., timeString= , ...)} \\
!          "string isofrac" - prints {\tt time}'s value in strict ISO 8601
!                     format for all units, including any fractional seconds
!                     part.  Format is YYYY-MM-DDThh:mm:ss[.f] where [.f]
!                     represents fractional seconds in decimal form, if present.
!                     See ~\cite{ISO} and ~\cite{ISOnotes}.  See also method
!                     {\tt ESMF\_TimeGet(..., timeStringISOFrac= , ...)} \\
!     \item[{[preString]}]
!          Optionally prepended string. Default to empty string.
!     \item[{[unit]}]
!          Internal unit, i.e. a string. Default to printing to stdout.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
! !REQUIREMENTS:
!     TMGn.n.n
      integer :: localrc                        ! local return code
      integer :: yy, mm, dd, h, m, s, ms
      logical :: underscore

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL
   
      ! check input
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,rc)

      underscore = .false.
      if (present(options)) then
        if (trim(options)=="underscore") underscore = .true.
      endif

      if (present(unit).or.present(preString)) then
        ! simple, single line print format
        call ESMF_TimeGet(time, yy=yy, mm=mm, dd=dd, h=h, m=m, s=s, ms=ms, &
          rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
        if (present(unit)) then
          if (underscore) then
            if (present(preString)) then
              write (unit, "(A, '_', I4.4, '_', I2.2, '_', I2.2, '_', I2.2, "//&
                "'_', I2.2, '_', I2.2, '_', I3.3)") preString, &
                yy, mm, dd, h, m, s, ms
            else
              write (unit, "(I4.4, '_', I2.2, '_', I2.2, '_', I2.2, "//&
                "'_', I2.2, '_', I2.2, '_', I3.3)") &
                yy, mm, dd, h, m, s, ms
            endif
          else
            if (present(preString)) then
              write (unit, "(A, I4, I3, I3, I3, I3, I3, I4)") preString, &
                yy, mm, dd, h, m, s, ms
            else
              write (unit, "(I4, I3, I3, I3, I3, I3, I4)") &
                yy, mm, dd, h, m, s, ms
            endif
          endif
        else
          if (present(preString)) then
            write (*, "(A, I4, I3, I3, I3, I3, I3, I4)") preString, &
              yy, mm, dd, h, m, s, ms
          else
            ! cannot really reach this branch -> cover this by the deeper
            ! implementation in the bigger else block below.
            write (*, "(I4, I3, I3, I3, I3, I3, I4)") &
              yy, mm, dd, h, m, s, ms
          endif
        endif        
      else
        ! print to STDOUT
        
        ! invoke C to C++ entry point
        call ESMF_UtilIOUnitFlush (ESMF_UtilIOStdout, rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

        call c_ESMC_TimePrint(time, options, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
      endif

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimePrint

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeReadRestart()"
!BOPI
! !IROUTINE:  ESMF_TimeReadRestart - Restore the contents of a Time (not implemented)

! !INTERFACE:
      subroutine ESMF_TimeReadRestart(time, name, keywordEnforcer, rc)
!
! !ARGUMENTS:
      type(ESMF_Time),   intent(inout)         :: time
      character (len=*), intent(in)            :: name
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,           intent(out), optional :: rc

! !DESCRIPTION:
!     Restores an {\tt ESMF\_Time} object from the last call to
!     {\tt ESMF\_TimeWriteRestart()}.  (Not implemented yet).
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          Restore into this {\tt ESMF\_Time}.
!     \item[name]
!          Restore from this object name.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOPI
! !REQUIREMENTS:
!     TMGn.n.n

      ! get length of given name for C++ validation
      integer :: nameLen, localrc

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      nameLen = len_trim(name)
   
      ! invoke C to C++ entry point to restore time
      call c_ESMC_TimeReadRestart(time, nameLen, name, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! mark output as successfully initialized
      call ESMF_TimeInit(time)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeReadRestart

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeSetDefault()"
!BOP
! !IROUTINE: ESMF_TimeSet - Initialize or set a Time

! !INTERFACE:
  ! Private name; call using ESMF_TimeSet()
      subroutine ESMF_TimeSetDefault(time, keywordEnforcer, &
        yy, yy_i8, &
        mm, dd, &
        d, d_i8, &
        h, m, &
        s, s_i8, &
        ms, us, ns, &
        d_r8, h_r8, m_r8, s_r8, &
        ms_r8, us_r8, ns_r8, &
        sN, sN_i8, sD, sD_i8, &
        calendar, calkindflag, &
        timeZone, rc)

! !ARGUMENTS:
      type(ESMF_Time),         intent(inout)         :: time
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer(ESMF_KIND_I4),   intent(in),  optional :: yy
      integer(ESMF_KIND_I8),   intent(in),  optional :: yy_i8
      integer,                 intent(in),  optional :: mm
      integer,                 intent(in),  optional :: dd
      integer(ESMF_KIND_I4),   intent(in),  optional :: d
      integer(ESMF_KIND_I8),   intent(in),  optional :: d_i8
      integer(ESMF_KIND_I4),   intent(in),  optional :: h
      integer(ESMF_KIND_I4),   intent(in),  optional :: m
      integer(ESMF_KIND_I4),   intent(in),  optional :: s
      integer(ESMF_KIND_I8),   intent(in),  optional :: s_i8
      integer(ESMF_KIND_I4),   intent(in),  optional :: ms
      integer(ESMF_KIND_I4),   intent(in),  optional :: us
      integer(ESMF_KIND_I4),   intent(in),  optional :: ns
      real(ESMF_KIND_R8),      intent(in),  optional :: d_r8
      real(ESMF_KIND_R8),      intent(in),  optional :: h_r8
      real(ESMF_KIND_R8),      intent(in),  optional :: m_r8
      real(ESMF_KIND_R8),      intent(in),  optional :: s_r8
      real(ESMF_KIND_R8),      intent(in),  optional :: ms_r8
      real(ESMF_KIND_R8),      intent(in),  optional :: us_r8
      real(ESMF_KIND_R8),      intent(in),  optional :: ns_r8
      integer(ESMF_KIND_I4),   intent(in),  optional :: sN
      integer(ESMF_KIND_I8),   intent(in),  optional :: sN_i8
      integer(ESMF_KIND_I4),   intent(in),  optional :: sD
      integer(ESMF_KIND_I8),   intent(in),  optional :: sD_i8
      type(ESMF_Calendar),     intent(in),  optional :: calendar
      type(ESMF_CalKind_Flag), intent(in),  optional :: calkindflag
      integer,                 intent(in),  optional :: timeZone ! not imp
      integer,                 intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Initializes an {\tt ESMF\_Time} with a set of user-specified units
!     via Fortran optional arguments.
!
!     The range of valid values for mm and dd depend on the calendar used.
!     For Gregorian, Julian, and No-Leap calendars, mm is [1-12] and dd is
!     [1-28,29,30, or 31], depending on the value of mm and whether yy or
!     yy\_i8 is a leap year.  For the 360-day calendar, mm is [1-12] and dd is
!     [1-30].  For Julian Day, Modified Julian Day, and No-Calendar,
!     yy, yy\_i8, mm, and dd are invalid inputs, since these calendars do not
!     define them.  When valid, the yy and yy\_i8 arguments should be fully
!     specified, e.g. 2003 instead of 03.  yy and yy\_i8 ranges are only
!     limited by machine word size, except for the Gregorian and Julian
!     calendars, where the lowest (proleptic) date limits are 3/1/-4800 and
!     3/1/-4712, respectively.  This is a limitation of the Gregorian
!     date-to-Julian day and Julian date-to-Julian day conversion algorithms
!     used to convert Gregorian and Julian dates to the internal representation
!     of seconds.  See~\cite{Fli68} for a description of the Gregorian
!     date-to-Julian day algorithm and~\cite{Hat84} for a description of the
!     Julian date-to-Julian day algorithm.  The Custom calendar will have
!     user-defined values for yy, yy\_i8, mm, and dd.
!
!     The Julian day specifier, d or d\_i8, can only be used with the
!     Julian Day and Modified Julian Day calendars, and has a valid range
!     depending on the word size.  For a signed 32-bit d, the range for
!     Julian day is [+/- 24855].  For a signed 64-bit d\_i8, the valid
!     range for Julian day is [+/- 106,751,991,167,300].  The Julian day
!     number system adheres to the conventional standard where the reference
!     day of d=0 corresponds to 11/24/-4713 in the proleptic Gregorian calendar
!     and 1/1/-4712 in the proleptic Julian calendar.  See~\cite{Meyer2} and
!     ~\cite{JDNcalculator}.
!
!     The Modified Julian Day system, introduced by space scientists in the late
!     1950's, is defined as Julian Day - 2400000.5.  See~\cite{MJD}.
!
!     Note that d and d\_i8 are not valid for the No-Calendar.  To remain
!     consistent with non-Earth calendars added to ESMF in the future, ESMF
!     requires a calendar to be planet-specific.  Hence the No-Calendar does
!     not know what a day is; it cannot assume an Earth day of 86400 seconds.
!
!     Hours, minutes, seconds, and sub-seconds can be used with any calendar,
!     since they are standardized units that are the same for any planet.
!
!     Time manager represents and manipulates time internally with integers
!     to maintain precision. Hence, user-specified floating point values are
!     converted internally to integers.  Sub-second values are represented
!     internally with an integer numerator and denominator fraction (sN/sD).
!     The smallest required resolution is nanoseconds (denominator).
!     For example, pi can be represented as s=3,
!     sN=141592654, sD=1000000000.  However, via sN\_i8 and sD\_i8, larger
!     values can be used.  If specifying a constant floating point value, be
!     sure to provide at least 16 digits to take full advantage of double
!     precision, for example s\_r8=2.718281828459045d0 for 'e' seconds.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to initialize.
!     \item[{[yy]}]
!          Integer year (32-bit).  Default = 0.
!     \item[{[yy\_i8]}]
!          Integer year (large, 64-bit).  Default = 0.
!     \item[{[mm]}]
!          Integer month.  Default = 1.
!     \item[{[dd]}]
!          Integer day of the month.  Default = 1.
!     \item[{[d]}]
!          Integer Julian Day, or Modified Julian Day (32-bit).  Must not be
!          specified with Gregorian calendars.  Default = 0.
!     \item[{[d\_i8]}]
!          Integer Julian Day, or Modified Julian Day (large, 64-bit).  Must not be
!          specified with Gregorian calendars.  Default = 0.
!     \item[{[h]}]
!          Integer hour.  Default = 0.
!     \item[{[m]}]
!          Integer minute.  Default = 0.
!     \item[{[s]}]
!          Integer second (32-bit).  Default = 0.
!     \item[{[s\_i8]}]
!          Integer second (large, 64-bit).  Default = 0.
!     \item[{[ms]}]
!          Integer millisecond.  Default = 0.
!     \item[{[us]}]
!          Integer microsecond.  Default = 0.
!     \item[{[ns]}]
!          Integer nanosecond.  Default = 0.
!     \item[{[d\_r8]}]
!          Double precision day.  Default = 0.0.
!     \item[{[h\_r8]}]
!          Double precision hour.  Default = 0.0.
!     \item[{[m\_r8]}]
!          Double precision minute.  Default = 0.0.
!     \item[{[s\_r8]}]
!          Double precision second.  Default = 0.0.
!     \item[{[ms\_r8]}]
!          Double precision millisecond.  Default = 0.0.
!     \item[{[us\_r8]}]
!          Double precision microsecond.  Default = 0.0.
!     \item[{[ns\_r8]}]
!          Double precision nanosecond.  Default = 0.0.
!     \item[{[sN]}]
!          Integer numerator of fractional second (sN/sD).
!          Default = 0.
!     \item[{[sN\_i8]}]
!          Integer numerator of fractional second (sN\_i8/sD\_i8)
!                                                           (large, 64-bit).
!          Default = 0.
!     \item[{[sD]}]
!          Integer denominator of fractional second (sN/sD).
!          Default = 1.
!     \item[{[sD\_i8]}]
!          Integer denominator of fractional second (sN\_i8/sD\_i8)
!                                                           (large, 64-bit).
!          Default = 1.
!     \item[{[calendar]}]
!          \begin{sloppypar}
!          Associated {\tt Calendar}.  Defaults to calendar
!          {\tt ESMF\_CALKIND\_NOCALENDAR} or default specified in
!          {\tt ESMF\_Initialize()} or {\tt ESMF\_CalendarSetDefault()}.
!          Alternate to, and mutually exclusive with, calkindflag
!          below.  Primarily for specifying a custom calendar kind.
!          \end{sloppypar}
!     \item[{[calkindflag]}]
!          Alternate to, and mutually exclusive with, calendar above.  More
!          convenient way of specifying a built-in calendar kind.
!     \item[{[timeZone]}]
!          Associated timezone (hours offset from UTC, e.g. EST = -5).
!          Default = 0 (UTC).  (Not implemented yet).
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
! !REQUIREMENTS:
!     TMGn.n.n
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! use optional args for any subset
      call c_ESMC_TimeSet(time, yy, yy_i8, mm, dd, d, d_i8, &
                          h, m, s, s_i8, ms, us, ns, &
                          d_r8, h_r8, m_r8, s_r8, ms_r8, us_r8, ns_r8, &
                          sN, sN_i8, sD, sD_i8, &
                          calendar, calkindflag, timeZone, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! mark output variable as successfully initialized
      call ESMF_TimeInit(time)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeSetDefault

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeSetString()"
!BOP
! !IROUTINE: ESMF_TimeSet - Initialize or set a Time from ISO format string

! !INTERFACE:
  ! Private name; call using ESMF_TimeSet()
      subroutine ESMF_TimeSetString(time, timeString, rc)

! !ARGUMENTS:
      type(ESMF_Time),         intent(inout)         :: time
      character(*),            intent(in)            :: timeString
      integer,                 intent(out), optional :: rc

!
! !DESCRIPTION:
!     Initializes an {\tt ESMF\_Time} with a set of user-specified string.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to initialize.
!     \item[timeString]
!          ISO format time string. E.g. 2012-10-24T18:00:00.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
      integer :: localrc                        ! local return code
      integer :: yy, mm, dd, h, m, s

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! transform from string to integer components
      read (timeString(1:4), "(I4.4)") yy
      read (timeString(6:7), "(I2.2)") mm
      read (timeString(9:10), "(I2.2)") dd
      read (timeString(12:13), "(I2.2)") h
      read (timeString(15:16), "(I2.2)") m
      read (timeString(18:19), "(I2.2)") s

      ! set the time using integer components
      call ESMF_TimeSet(time, yy=yy, mm=mm, dd=dd, h=h, m=m, s=s, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeSetString

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeSyncToRealTime()"
!BOP
! !IROUTINE: ESMF_TimeSyncToRealTime - Get system real time (wall clock time)
!
! !INTERFACE:
      subroutine ESMF_TimeSyncToRealTime(time, keywordEnforcer, rc)
!
! !ARGUMENTS:
      type(ESMF_Time), intent(inout) :: time
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer, intent(out), optional :: rc
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Gets the system real time (wall clock time), and returns it as an
!     {\tt ESMF\_Time}.  Accurate to the nearest second.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to receive the real time.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
! !REQUIREMENTS:
!     TMG2.5.7
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,rc)

      ! invoke C to C++ entry point
      call c_ESMC_TimeSyncToRealTime(time, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeSyncToRealTime

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeValidate()"
!BOP
! !IROUTINE:  ESMF_TimeValidate - Validate a Time

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

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

!
! !DESCRIPTION:
!     Checks whether an {\tt ESMF\_Time} is valid.
!     Must be a valid date/time on a valid calendar.
!     The options control the type of validation.
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          {\tt ESMF\_Time} instant to be validated.
!     \item[{[options]}]
!          Validation options. If none specified, validates all {\tt time} property
!            values. \\
!          "calendar" - validate only the {\tt time}'s calendar. \\
!          "timezone" - validate only the {\tt time}'s timezone. \\
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
! !REQUIREMENTS:
!     TMGn.n.n
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,rc)
   
      ! invoke C to C++ entry point
      call c_ESMC_TimeValidate(time, options, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeValidate

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeWriteRestart()"
!BOPI
! !IROUTINE:  ESMF_TimeWriteRestart - Save the contents of a Time (not implemented)

! !INTERFACE:
      subroutine ESMF_TimeWriteRestart(time, keywordEnforcer, rc)

! !ARGUMENTS:
      type(ESMF_Time),   intent(in)            :: time
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,           intent(out), optional :: rc

! !DESCRIPTION:
!     Saves an {\tt ESMF\_Time} object.  Default options are to select the
!     fastest way to save to disk.  (Not implemented yet).
!
!     The arguments are:
!     \begin{description}
!     \item[time]
!          The object instance to save.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOPI
! !REQUIREMENTS:
!     TMGn.n.n
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,rc)
   
      ! invoke C to C++ entry point
      call c_ESMC_TimeWriteRestart(time, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_TimeWriteRestart

!------------------------------------------------------------------------------
!
! This section includes the inherited ESMC_BaseTime class overloaded operators
! internal, private implementation methods.
! Note:  these functions do not have a return code, since Fortran forbids more
! than 2 arguments for arithmetic overloaded operators
!
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeInc()"
!BOPI
! !IROUTINE: ESMF_TimeInc - Increment a Time with a TimeInterval
!
! !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
!
! !DESCRIPTION:
!     This method overloads the (+) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(+)" above for complete description.
!
!EOPI
      integer :: localrc

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeIntervalGetInit,timeinterval,localrc)

      ! invoke C to C++ entry point
      call c_ESMC_TimeInc(time, timeinterval, ESMF_TimeInc)

      ! mark output as successfully initialized
      call ESMF_TimeInit(ESMF_TimeInc)

      end function ESMF_TimeInc
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeDec()"
!BOPI
! !IROUTINE: ESMF_TimeDec - Decrement a Time with a TimeInterval
!
! !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
!
! !DESCRIPTION:
!     This method overloads the (-) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(-)" above for complete description.
!
!EOPI
      integer :: localrc

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeIntervalGetInit,timeinterval,localrc)

      ! invoke C to C++ entry point
      call c_ESMC_TimeDec(time, timeinterval, ESMF_TimeDec)

      ! mark output as successfully initialized
      call ESMF_TimeInit(ESMF_TimeDec)

      end function ESMF_TimeDec

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeDiff()"
!BOPI
! !IROUTINE:  ESMF_TimeDiff - Return the difference between two Times
!
! !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

! !DESCRIPTION:
!     This method overloads the (-) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(-)" above for complete description.
!
!EOPI
      integer :: localrc

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,localrc)

      ! invoke C to C++ entry point
      call c_ESMC_TimeDiff(time1, time2, ESMF_TimeDiff)

      ! mark output as successfully initialized
      call ESMF_TimeIntervalInit(ESMF_TimeDiff)

      end function ESMF_TimeDiff

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeEQ()"
!BOPI
! !IROUTINE: ESMF_TimeEQ - Test if Time 1 is equal to Time 2
!
! !INTERFACE:
      impure elemental function ESMF_TimeEQ(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeEQ
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2
!
! !DESCRIPTION:
!     This method overloads the (==) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(==)" above for complete description.
!
!EOPI
      integer :: localrc

      ! Initialize output value in case of error
      ESMF_TimeEQ = .false.

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,localrc)

      ! invoke C to C++ entry point for ESMC_BaseTime base class function
      call c_ESMC_BaseTimeEQ(time1, time2, ESMF_TimeEQ)

      end function ESMF_TimeEQ

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeNE()"
!BOPI
! !IROUTINE: ESMF_TimeNE - Test if Time 1 is not equal to Time 2
!
! !INTERFACE:
      impure elemental function ESMF_TimeNE(time1, time2)
!
! !RETURN VALUE:
      logical :: ESMF_TimeNE
!
! !ARGUMENTS:
      type(ESMF_Time), intent(in) :: time1
      type(ESMF_Time), intent(in) :: time2

! !DESCRIPTION:
!     This method overloads the (/=) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(/=)" above for complete description.
!
!EOPI
      integer :: localrc

      ! Initialize output value in case of error
      ESMF_TimeNE = .true.

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,localrc)

      ! invoke C to C++ entry point for ESMC_BaseTime base class function
      call c_ESMC_BaseTimeNE(time1, time2, ESMF_TimeNE)

      end function ESMF_TimeNE

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeLT()"
!BOPI
! !IROUTINE: ESMF_TimeLT - Test if Time 1 is less than Time 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:
!     This method overloads the (<) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(<)" above for complete description.
!
!EOPI
      integer :: localrc

      ! Initialize output value in case of error
      ESMF_TimeLT = .false.

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,localrc)

      ! invoke C to C++ entry point for ESMC_BaseTime base class function
      call c_ESMC_BaseTimeLT(time1, time2, ESMF_TimeLT)

      end function ESMF_TimeLT

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeLE()"
!BOPI
! !IROUTINE: ESMF_TimeLE - Test if Time 1 is less than or equal to Time 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:
!     This method overloads the (<=) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(<=)" above for complete description.
!
!EOPI
      integer :: localrc

      ! Initialize output value in case of error
      ESMF_TimeLE = .false.

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,localrc)

      ! invoke C to C++ entry point for ESMC_BaseTime base class function
      call c_ESMC_BaseTimeLE(time1, time2, ESMF_TimeLE)

      end function ESMF_TimeLE

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeGT()"
!BOPI
! !IROUTINE: ESMF_TimeGT - Test if Time 1 is greater than Time 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:
!     This method overloads the (>) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(>)" above for complete description.
!
!EOPI
      integer :: localrc

      ! Initialize output value in case of error
      ESMF_TimeGT = .false.

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,localrc)

      ! invoke C to C++ entry point for ESMC_BaseTime base class function
      call c_ESMC_BaseTimeGT(time1, time2, ESMF_TimeGT)

      end function ESMF_TimeGT

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_TimeGE()"
!BOPI
! !IROUTINE: ESMF_TimeGE - Test if Time 1 is greater than or equal to Time 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:
!     This method overloads the (>=) operator for the {\tt ESMF\_Time} class.
!     See "interface operator(>=)" above for complete description.
!
!EOPI
      integer :: localrc

      ! Initialize output value in case of error
      ESMF_TimeGE = .false.

      ! check inputs
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time1,localrc)
      ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,time2,localrc)

      ! invoke C to C++ entry point for ESMC_BaseTime base class function
      call c_ESMC_BaseTimeGE(time1, time2, ESMF_TimeGE)

      end function ESMF_TimeGE

!------------------------------------------------------------------------------

      end module ESMF_TimeMod
