
c   no cpp defines here

       module time_type_module
       implicit none
!====================================================================
! The module provides a single defined type, time_type, which is 
! used to store time and date quantities. A time_type is a positive 
! definite quantity that represents an interval of time. It can be most 
! easily thought of as representing the number of seconds in some time 
! interval. A time interval can be mapped to a date under a given calendar 
! definition by using it to represent the time that has passed since some 
! base date. A number of interfaces are provided to operate on time_type 
! variables and their associated calendars. Time intervals can be as large 
! as n days where n is the largest number represented by the default integer 
! type on a compiler. This is typically considerably greater than 10 million 
! years which is likely to be adequate for most applications. The 
! description of the interfaces is separated into two sections. The first 
! deals with operations on time intervals while the second deals with 
! operations that convert time intervals to dates for a given calendar.
!
!     author: Jeff Anderson         jla@gfdl.gov 
c     SPFLAME version : c.eden
!====================================================================

        public time_type
	type :: time_type
	   integer:: seconds
	   integer:: days
	end type time_type

	public operator( + ),  operator( - ),   operator( * ) 
        public operator( / )  
	public operator( > ),  operator( >= ),  operator( == )
        public operator( /= )
	public operator( < ),  operator( <= )

	interface operator (+) 
          module procedure time_plus
        end interface
	interface operator (-)   
          module procedure time_minus
        end interface
	interface operator (*)   
          module procedure time_scalar_mult 
          module procedure scalar_time_mult
        end interface
	interface operator (/)   
          module procedure time_scalar_divide
	  module procedure time_divide  
        end interface
	interface operator (>)   
          module procedure time_gt
        end interface
	interface operator (>=)  
          module procedure time_ge
        end interface
	interface operator (<)   
          module procedure time_lt
        end interface
	interface operator (<=)  
          module procedure time_le
        end interface
	interface operator (==)  
          module procedure time_eq
        end interface
	interface operator (/=)  
          module procedure time_ne
        end interface

	public  set_time 
        public  increment_time
        public  decrement_time
        public  time_in_days,time_in_secs

        public set_calendar_type
        public get_calendar_type

        public get_date
        private get_date_thirty,get_date_no_leap,get_date_julian

        public   set_date 
        private  set_date_thirty
        private  set_date_julian, set_date_no_leap

        public   increment_date 
        private  increment_thirty
        private  increment_julian
        private  increment_no_leap

        public   decrement_date 
        private  decrement_thirty
        private  decrement_julian
        private  decrement_no_leap

        private error_handler

	integer, parameter, public ::   
     &       THIRTY_DAY_MONTHS = 1, JULIAN = 2, 
     &	     NO_LEAP = 3,  NO_CALENDAR = 0

	integer,private ::calendar_type=NO_CALENDAR,max_type = 3

	integer, public  ::  
     &   days_per_month(12) = (/31,28,31,30,31,30,31,31,30,31,30,31/)

        contains


	subroutine set_time(time,seconds, days)
! Returns a time interval corresponding to this number of days and seconds.
! The arguments must not be negative but are otherwise unrestricted.
	implicit none
	type(time_type) :: time
	integer, intent(in) :: seconds, days
! Negative time offset is illegal
	if(seconds < 0 .or. days < 0) 
     &        call error_handler('Negative input in set_time')
! Make sure seconds greater than a day are fixed up
	time%seconds = seconds - seconds / (60*60*24) * (60*60*24)
	time%days = days + seconds / (60*60*24)
	end subroutine set_time

!-------------------------------------------------------------------------
	subroutine decrement_time(result,time, seconds, days)
! Decrements a time by seconds and days; decrements cannot be negative.
	implicit none
	type(time_type),intent(out) :: result
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, days
	integer :: cseconds, cdays
! Decrement must be positive definite
	if(seconds < 0 .or. days < 0) 
     &	   call error_handler('Negative decrement in decrement_time')
	cseconds = time%seconds - seconds
	cdays = time%days - days
! Borrow if needed
	if(cseconds < 0) then
	   cdays = cdays - 1 + (cseconds + 1) / (60*60*24)
	   cseconds = cseconds - (60*60*24) * (-1 + (cseconds + 1) 
     &                   / (60*60*24))
	end if
! Check for illegal negative time
	if(cdays < 0) call error_handler(
     & 'Negative time results in decrement_time')
	result%seconds = cseconds
	result%days = cdays
	end subroutine decrement_time

	subroutine increment_time(result,time, seconds, days)
! Increments a time by seconds and days; increments cannot be negative.
	implicit none
	type( time_type),intent(out) :: result
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, days
	integer :: s, d
! Increment must be positive definite
	if(seconds < 0 .or. days < 0) 
     &	   call error_handler('Negative increment in increment_time')
        s=time%seconds+seconds
        d=time%days+days
c	increment_time = set_time(s, d)
	call set_time(result,s, d)
c	increment_time%seconds = s - s / (60*60*24) * (60*60*24)
c	increment_time%days = d + s / (60*60*24)
	end subroutine increment_time

!-------------------------------------------------------------------------
        function time_in_days(time)
        implicit none
	type(time_type), intent(in) :: time
        real time_in_days
        time_in_days=time%days+time%seconds/24./60./60.
        end function time_in_days

        function time_in_secs(time)
        implicit none
	type(time_type), intent(in) :: time
        real time_in_secs
        time_in_secs=time%days*24.*60.*60.+time%seconds
        end function time_in_secs


!--------------------------------------------------------------------------
	function time_gt(time1, time2)
! Returns true if time1 > time2
	implicit none
	logical :: time_gt
	type(time_type), intent(in) :: time1, time2
	time_gt = (time1%days > time2%days)
	if(time1%days == time2%days) time_gt = (time1%seconds 
     &     > time2%seconds)
	end function time_gt
!--------------------------------------------------------------------------
	function time_ge(time1, time2)
! Returns true if time1 >= time2
	implicit none
	logical :: time_ge
	type(time_type), intent(in) :: time1, time2
	time_ge = (time_gt(time1, time2) .or. time_eq(time1, time2))
	end function time_ge
!--------------------------------------------------------------------------
	function time_lt(time1, time2)
! Returns true if time1 < time2
	implicit none
	logical :: time_lt
	type(time_type), intent(in) :: time1, time2
	time_lt = (time1%days < time2%days)
	if(time1%days == time2%days) time_lt = (time1%seconds 
     &               < time2%seconds)
	end function time_lt
!--------------------------------------------------------------------------
	function time_le(time1, time2)
! Returns true if time1 <= time2
	implicit none
	logical :: time_le
	type(time_type), intent(in) :: time1, time2
	time_le = (time_lt(time1, time2) .or. time_eq(time1, time2))
	end function time_le
!--------------------------------------------------------------------------
	function time_eq(time1, time2)
! Returns true if time1 == time2
	implicit none
	logical :: time_eq
	type(time_type), intent(in) :: time1, time2
	time_eq = (time1%seconds == time2%seconds .and. 
     &              time1%days == time2%days)
	end function time_eq
!--------------------------------------------------------------------------
	function time_ne(time1, time2)
! Returns true if time1 /= time2
	implicit none
	logical :: time_ne
	type(time_type), intent(in) :: time1, time2
	time_ne = (.not. time_eq(time1, time2))
	end function time_ne
!-------------------------------------------------------------------------
	function time_plus(time1, time2)
! Returns sum of two time_types
	implicit none
	type(time_type) :: time_plus
	type(time_type), intent(in) :: time1, time2
c	time_plus = increment_time(time1, time2%seconds, time2%days)
	call increment_time(time_plus ,time1, time2%seconds, time2%days)
	end function time_plus
!-------------------------------------------------------------------------
	function time_minus(time1, time2)
! Returns difference of two time_types. WARNING: a time type is positive 
! so by definition time1 - time2  is the same as time2 - time1.
	implicit none
	type(time_type) :: time_minus
	type(time_type), intent(in) :: time1, time2
	if(time1 > time2) then
c	   time_minus = decrement_time(time1, time2%seconds, time2%days)
        call decrement_time(time_minus,time1, time2%seconds, time2%days)
	else 
c	   time_minus = decrement_time(time2, time1%seconds, time1%days)
       call decrement_time(time_minus ,time2, time1%seconds, time1%days)
	endif
	end function time_minus
!--------------------------------------------------------------------------
	function time_scalar_mult(time, n)
	! Returns time multiplied by integer factor n
	implicit none
	type(time_type) :: time_scalar_mult,time2
	type(time_type), intent(in) :: time
	integer, intent(in) :: n
	integer :: days, seconds
	double precision :: sec_prod 
! Multiplying here in a reasonable fashion to avoid overflow is tricky
! Could multiply by some large factor n, and seconds could be up to 86399
! Need to avoid overflowing integers and wrapping around to negatives
	sec_prod = dble(time%seconds) * dble(n)
! If sec_prod is large compared to precision of double precision, things
! can go bad.  Need to warn and abort on this.
	if(sec_prod /= 0.0) then
	   if(log10(sec_prod) > precision(sec_prod) - 3) 
     & call error_handler(
     & 'Insufficient precision to handle scalar product in '//
     & 'time_scalar_mult; contact developer')
	end if
	days = sec_prod / dble(24. * 60. * 60.)
	seconds = sec_prod - dble(days) * dble(24. * 60. * 60.)
c	time_scalar_mult = set_time(seconds, time%days * n + days)
	call set_time(time2 ,seconds, time%days * n + days)
	time_scalar_mult =time2
	end function time_scalar_mult
!-------------------------------------------------------------------------
	function scalar_time_mult(n, time)
! Returns time multipled by integer factor n
	implicit none
	type(time_type) :: scalar_time_mult
	type(time_type), intent(in) :: time
	integer, intent(in) :: n
	scalar_time_mult = time_scalar_mult(time, n)
	end function scalar_time_mult
!-------------------------------------------------------------------------
	function time_divide(time1, time2)
! Returns the largest integer, n, for which time1 >= time2 * n.
	implicit none
	integer :: time_divide
	type(time_type), intent(in) :: time1, time2
	double precision :: d1, d2
! Convert time intervals to floating point days; risky for general performance?
	d1 = time1%days * dble(60. * 60. * 24.) + dble(time1%seconds)
	d2 = time2%days * dble(60. * 60. * 24.) + dble(time2%seconds) 
! Get integer quotient of this, check carefully to avoid round-off problems.
	time_divide = d1 / d2
! Verify time_divide*time2 is <= time1 and (time_divide + 1)*time2 is > time1
	if(time_divide * time2 > time1 .or. (time_divide + 1) 
     & * time2 <= time1)  call error_handler(
     & 'time_divide quotient error :: notify developer')
	end function time_divide
!-------------------------------------------------------------------------
c	function time_real_divide(time1, time2)
! Returns the double precision quotient of two times
c	implicit none
c	double precision :: time_real_divide
c	type(time_type), intent(in) :: time1, time2
c	double precision :: d1, d2
! Convert time intervals to floating point days; risky for general performance?
c	d1 = time1%days * dble(60. * 60. * 24.) + dble(time1%seconds)
c	d2 = time2%days * dble(60. * 60. * 24.) + dble(time2%seconds) 
c	time_real_divide = d1 / d2
c	end function time_real_divide
!-------------------------------------------------------------------------
	function time_scalar_divide(time, n)
! Returns the largest time, t, for which n * t <= time
	implicit none
	type(time_type) :: time_scalar_divide
	type(time_type), intent(in) :: time
	integer, intent(in) :: n
	double precision :: d, div
	integer :: days, seconds
	type(time_type) :: prod1, prod2
! Convert time interval to floating point days; risky for general performance?
	d = time%days * dble(60.*60.*24.) + dble(time%seconds)
	div = d / dble(1.0 * n)
	days = div / dble(60.*60.*24.)
	seconds = div - days * dble(60.*60.*24.)
c	time_scalar_divide = set_time(seconds, days)
	call set_time(time_scalar_divide ,seconds, days)
! Need to make sure that roundoff isn`t killing this
	prod1 = n * time_scalar_divide
c	prod2 = n * (increment_time(time_scalar_divide, 1, 0)) 
	call increment_time(prod2 ,time_scalar_divide, 1, 0) 
	prod2 = n * prod2
	if(prod1 > time .or. prod2 <= time) call error_handler(
     & 'time_scalar_divide quotient error :: notify developer')
	end function time_scalar_divide
!-------------------------------------------------------------------------




	subroutine set_calendar_type(type)
! Selects calendar for default mapping from time to date. 
	implicit none
	integer, intent(in) :: type
	if(type <= 0 .or. type > max_type) 
     &	   call error_handler('Illegal type in set_calendar_type')
	calendar_type = type
        if (type ==  THIRTY_DAY_MONTHS) then
         days_per_month = (/30,30,30,30,30,30,30,30,30,30,30,30/)
        else
         days_per_month = (/31,28,31,30,31,30,31,31,30,31,30,31/)
        endif
	end subroutine set_calendar_type

!------------------------------------------------------------------------
	function get_calendar_type()
! Returns default calendar type for mapping from time to date.
	implicit none
	integer :: get_calendar_type
	get_calendar_type = calendar_type
	end function get_calendar_type
!========================================================================
	subroutine get_date(time, year, month,day,hour,minute,second)
! Given a time, computes the corresponding date given the selected calendar
	implicit none
	type(time_type), intent(in) :: time
	integer, intent(out) :: second, minute, hour, day, month, year
	select case(calendar_type)
	case(THIRTY_DAY_MONTHS)
	   call get_date_thirty(time, year, month, day, hour,
     &  minute, second)
	case(JULIAN)
	   call get_date_julian(time, year, month, day, hour,
     &  minute, second)
	case(NO_LEAP)
	   call get_date_no_leap(time, year, month, day, hour, 
     &  minute, second)
	case default
	   call error_handler('Invalid calendar type in get_date')
	end select
	end subroutine get_date
!------------------------------------------------------------------------

	subroutine get_date_julian(time, year, month, day, hour, 
     & minute, second)
! Base date for Julian calendar is year 1 with all multiples of 4 
! years being leap years.
	implicit none
	type(time_type), intent(in) :: time
	integer, intent(out) :: second, minute, hour, day, month, year
	integer :: m, t, nfour, nex, days_this_month
	logical :: leap
! find number of four year periods; also get modulo number of days
	nfour = time%days / (4 * 365 + 1) 
	day = modulo(time%days, (4 * 365 + 1))
! Find out what year in four year chunk
	nex = day / 365
	if(nex == 4) then
	   nex = 3
	   day = 366
	else
	   day=modulo(day, 365) + 1
	endif
! Is this a leap year? 
	leap = (nex == 3)
	year = 1 + 4 * nfour + nex
! find month and day
	do m = 1, 12
	   month = m
	   days_this_month = days_per_month(m)
	   if(leap .and. m == 2) days_this_month = 29
	   if(day <= days_this_month) exit
	   day = day - days_this_month
	end do
! find hour,minute and second
	t = time%seconds
	hour = t / (60 * 60)
	t = t - hour * (60 * 60)
	minute = t / 60
	second = t - 60 * minute
	end subroutine get_date_julian
!------------------------------------------------------------------------
	subroutine get_date_thirty(time, year, month, day, hour, 
     & minute, second)
! Computes date corresponding to time interval for 30 day months, 12
! month years.
	implicit none
	type(time_type), intent(in) :: time
	integer, intent(out) :: second, minute, hour, day, month, year
	integer :: t, dmonth, dyear
	t = time%days
	dyear = t / (30 * 12)
	year = dyear + 1
	t = t - dyear * (30 * 12)
	dmonth = t / 30
	month = 1 + dmonth
	day = t -dmonth * 30 + 1
	t = time%seconds
	hour = t / (60 * 60) 
	t = t - hour * (60 * 60)
	minute = t / 60
	second = t - 60 * minute
	end subroutine get_date_thirty
!------------------------------------------------------------------------
	subroutine get_date_no_leap(time, year, month, day, hour, 
     &  minute, second)
! Base date for no_leap calendar is year 1.
	implicit none
	type(time_type), intent(in) :: time
	integer, intent(out) :: second, minute, hour, day, month, year
	integer :: m, t
! get modulo number of days
	year = time%days / 365 + 1
	day = modulo(time%days, 365) + 1
! find month and day
	do m = 1, 12
	   month = m
	   if(day <= days_per_month(m)) exit
	   day = day - days_per_month(m)
	end do
! find hour,minute and second
	t = time%seconds
	hour = t / (60 * 60)
	t = t - hour * (60 * 60)
	minute = t / 60
	second = t - 60 * minute
	end subroutine get_date_no_leap
!========================================================================
	function set_date(year, month, day, hours, minutes, seconds)
! Given a date, computes the corresponding time given the selected
! date time mapping algorithm.  Note that it is possible to specify
! any number of illegal dates; these should be checked for and generate
! errors as appropriate.
	implicit none
	type(time_type) :: set_date
	integer, intent(in) :: day, month, year
	integer, intent(in) :: seconds, minutes, hours
	select case(calendar_type)
	case(THIRTY_DAY_MONTHS)
	   set_date = set_date_thirty(year, month, day, hours, 
     &  minutes, seconds)
	case(JULIAN)
	   set_date = set_date_julian(year, month, day, hours, 
     &  minutes, seconds)
	case(NO_LEAP)
	   set_date = set_date_no_leap(year, month, day, hours, 
     &  minutes, seconds)
	case default
	   call error_handler('Invalid calendar type in set_date')
	end select
	end function set_date
!------------------------------------------------------------------------
	function set_date_julian(year, month, day, hours, 
     & minutes, seconds)
! Returns time corresponding to date for julian calendar.
	implicit none
	type(time_type) :: set_date_julian
	integer, intent(in) :: day, month, year
	integer, intent(in) :: seconds, minutes, hours
	integer ndays, m, nleapyr
	logical :: leap
! Need to check for bogus dates
	if(seconds > 59 .or. seconds < 0 .or. minutes > 59 
     & .or. minutes < 0 .or. hours > 23 .or. hours < 0 .or. day < 1 
     & .or. month > 12 .or. month < 1 .or. year < 1) 
     &	   call error_handler('Invalid date in set_date_julian')
	if(month /= 2 .and. day > days_per_month(month)) 
     &	   call error_handler('Invalid day in set_date_julian')
! Is this a leap year? 
	leap = (modulo(year,4) == 0)
! compute number of complete leap years from year 1
	nleapyr = (year - 1) / 4
! Finish checking for day specication errors
	if(month == 2 .and. (day > 29 .or. ((.not. leap) .and. 
     & day > 28))) call error_handler(
     & 'Invalid number of days in month 2 in set_date_julian')
	ndays = 0
	do m = 1, month - 1
	   ndays = ndays + days_per_month(m)
	   if(leap .and. m == 2) ndays = ndays + 1
	enddo
	set_date_julian%seconds = seconds + 60 * (minutes + 
     & 60 * hours)
	set_date_julian%days = day -1 + ndays + 365*(year - nleapyr 
     & - 1) + 366*(nleapyr)
	end function set_date_julian
!------------------------------------------------------------------------

	function set_date_thirty(year, month, day, hours, 
     &  minutes, seconds)
	! Computes time corresponding to date for thirty day months.
	implicit none
	type(time_type) :: set_date_thirty
	integer, intent(in) :: day, month, year
	integer, intent(in) :: seconds, minutes, hours
	! Need to check for bogus dates
	if(seconds > 59 .or. seconds < 0 .or. minutes > 59 .or. 
     &   minutes < 0 .or. hours > 23 .or. hours < 0 .or. day > 30 
     &   .or. day < 1 .or. month > 12 .or. month < 1 .or. year < 1) 
     &	      call error_handler('Invalid date in set_date_thirty')
	set_date_thirty%days = (day - 1) + 30 * ((month - 1) + 
     & 12 * (year - 1))
	set_date_thirty%seconds = seconds + 60 * (minutes + 
     & 60 * hours)
	end function set_date_thirty
!------------------------------------------------------------------------
	function set_date_no_leap(year, month, day, hours, 
     &   minutes, seconds)
! Computes time corresponding to date for fixed 365 day year calendar.
	implicit none
	type(time_type) :: set_date_no_leap,time2
	integer, intent(in) :: day, month, year
	integer, intent(in) :: seconds, minutes, hours
	integer ndays, m
	! Need to check for bogus dates
	if(seconds > 59 .or. seconds < 0 .or. minutes > 59 
     &  .or. minutes < 0 .or. hours > 23 .or. hours < 0 
     &  .or. day > 31 .or. day < 1 .or. month > 12 .or. month < 1 
     &   .or. year < 1) then
	   call error_handler('Invalid date in set_date_no_leap')
	endif
	ndays = 0
	do m = 1, month - 1
	   ndays = ndays + days_per_month(m)
	enddo
c	set_date_no_leap = set_time(seconds + 60 * 
	call set_time(time2 ,seconds + 60 * 
     &  (minutes + 60 * hours), day -1 + ndays + 365 * (year - 1))
        set_date_no_leap=time2
	end function set_date_no_leap
!------------------------------------------------------------------------
	function increment_date(time, years, months, days, 
     &  hours, minutes, seconds)
! Given a time and some date increment, computes a new time.  Depending
! on the mapping algorithm from date to time, it may be possible to specify
! undefined increments (i.e. if one increments by 68 days and 3 months in
! a Julian calendar, it matters which order these operations are done and
! we don`t want to deal with stuff like that, make it an error).
	implicit none
	type(time_type) :: increment_date
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, minutes, hours, 
     &  days, months, years
	select case(calendar_type)
	case(THIRTY_DAY_MONTHS)
	   increment_date = increment_thirty(time, years, months, 
     &              days, hours, minutes, seconds)
	case(JULIAN)
	   increment_date = increment_julian(time, years, months, 
     &              days, hours, minutes, seconds)
	case(NO_LEAP)
	   increment_date = increment_no_leap(time, years, months, 
     &              days, hours, minutes, seconds)
	case default
	   call error_handler('Invalid calendar type in increment_date')
	end select
	end function increment_date
!-------------------------------------------------------------------------
	function increment_julian(time, years, months, days, 
     & hours, minutes, seconds)
	! Given time and some date increment, computes new time for julian calendar.
	implicit none
	type(time_type) :: increment_julian
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, minutes, 
     &  hours, days, months, years
	integer :: csecond, cminute, chour, cday, cmonth, cyear, dyear
	type(time_type) :: t
! Increment must be positive definite
	if(seconds < 0 .or. minutes < 0 .or. hours < 0 
     & .or. days < 0 .or. months < 0 .or. years < 0) 
     &	   call error_handler('Illegal increment in increment_julian')
!  There are a number of other bad types of increments that should be
!  prohibited here; the addition is not associative
!  Easiest thing is to only let month and year be incremented by themselves
!  This is slight overkill since year is not really a problem.
	if(months /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     & .or. hours /= 0 .or. days /= 0 .or. years /= 0)) 
     &  call error_handler (
     &'increment_julian:month must not be incremented with other units')
	if(years /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     & .or. hours /= 0 .or. days /= 0 .or. months /= 0)) 
     &  call error_handler (
     &'increment_julian: year must not be incremented with other units')
!  For non-month and non-year part can just use increment_thirty
	t =  increment_thirty(time, 0, 0, days, hours, 
     & minutes, seconds)
!  For month or year increment, first convert to date
	call get_date_julian(t, cyear, cmonth, cday, chour, 
     & cminute, csecond)
	cmonth = cmonth + months
	cyear = cyear + years
! Check for months larger than 12 and fix
	if(cmonth > 12) then
	   dyear = (cmonth - 1) / 12 
	   cmonth = cmonth - 12 * dyear
	   cyear = cyear + dyear
	end if
! Convert this back into a time
	increment_julian = set_date_julian(cyear, cmonth, cday, chour, 
     & cminute, csecond)
	end function increment_julian
!-------------------------------------------------------------------------
	function increment_thirty(time, years, months, days, hours, 
     &  minutes, seconds)
! Given a time and some date increment, computes new time for thirty day months.
	implicit none
	type(time_type) :: increment_thirty,time2
	type(time_type), intent(in) :: time
	integer, intent(in):: seconds, minutes, hours, 
     & days, months, years
	integer :: csecond, cday
! Increment must be positive definite
	if(seconds < 0 .or. minutes < 0 .or. hours < 0 .or. 
     &   days < 0 .or. months < 0 .or. years < 0) 
     &	  call error_handler('Illegal increment in increment_thirty')
! Do increment to seconds portion first
	csecond = seconds + 60 * (minutes + 60 * hours)
	cday = days + 30 * (months + 12 * years)
c	increment_thirty = increment_time(time, csecond, cday)
	call increment_time(time2 ,time, csecond, cday)
	increment_thirty =time2
	end function increment_thirty
!-------------------------------------------------------------------------
	function increment_no_leap(time, years, months, days, 
     & hours, minutes, seconds)
! Given time and some date increment, computes new time for julian calendar.
	implicit none
        type(time_type) :: increment_no_leap
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, minutes, hours, 
     & days, months, years
	integer :: csecond, cminute, chour, cday, cmonth, cyear, dyear
	type(time_type) :: t
! Increment must be positive definite
	if(seconds < 0 .or. minutes < 0 .or. hours < 0 .or. 
     & days < 0 .or. months < 0 .or. years < 0) 
     &  call error_handler('Illegal increment in increment_no_leap')
!  There are a number of other bad types of increments that should be
!  prohibited here; the addition is not associative
!  Easiest thing is to only let month and year be incremented by themselves
!  This is slight overkill since year is not really a problem.
	if(months /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     & .or. hours /= 0 .or. days /= 0 .or. years /= 0)) 
     & call error_handler (
     &'increment_no_leap:month must notbe incremented with other units')
	if(years /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     & .or. hours /= 0 .or. days /= 0 .or. months /= 0)) 
     & call error_handler (
     &'increment_no_leap:year must not be incremented with other units')
!  For non-month and non-year part can just use increment_thirty
	t =  increment_thirty(time, 0, 0, days, hours, 
     &  minutes, seconds)
!  For month or year increment, first convert to date
	call get_date_no_leap(t, cyear, cmonth, cday, chour, 
     & cminute, csecond)
	cmonth = cmonth + months
	cyear = cyear + years
	! Check for months larger than 12 and fix
	if(cmonth > 12) then
	   dyear = (cmonth - 1) / 12 
	   cmonth = cmonth - 12 * dyear
	   cyear = cyear + dyear
	end if
! Convert this back into a time
	increment_no_leap = set_date_no_leap(cyear, cmonth, cday, 
     &   chour, cminute, csecond)
	end function increment_no_leap
!=========================================================================
	function decrement_date(time, years, months, days, 
     &      hours, minutes, seconds)
! Given a time and some date decrement, computes a new time.  Depending
! on the mapping algorithm from date to time, it may be possible to specify
! undefined decrements (i.e. if one decrements by 68 days and 3 months in
! a Julian calendar, it matters which order these operations are done and
! we don`t want to deal with stuff like that, make it an error).
	implicit none
	type(time_type) :: decrement_date
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, minutes, 
     &        hours, days, months, years
	select case(calendar_type)
	case(THIRTY_DAY_MONTHS)
	   decrement_date = decrement_thirty(time, years, months, 
     &       days, hours, minutes, seconds)
	case(JULIAN)
	   decrement_date = decrement_julian(time, years, months, 
     &       days, hours, minutes, seconds)
	case(NO_LEAP)
	   decrement_date = decrement_no_leap(time, years, months, 
     &       days, hours, minutes, seconds)
	case default
	   call error_handler('Invalid calendar type in decrement_date')
	end select
	end function decrement_date
!-------------------------------------------------------------------------
	function decrement_julian(time, years, months, days, hours, 
     &                            minutes, seconds)
! Given time and some date decrement, computes new time for julian calendar.
	implicit none
	type(time_type) :: decrement_julian
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, minutes, hours, 
     &                     days, months, years
	integer :: csecond, cminute, chour, cday, cmonth, cyear
	type(time_type) :: t
! Increment must be positive definite
	if(seconds < 0 .or. minutes < 0 .or. hours < 0 
     &    .or. days < 0 .or. months < 0 .or. years < 0) 
     &	   call error_handler('Illegal increment in decrement_julian')
!  There are a number of other bad types of decrements that should be
!  prohibited here; the subtraction is not associative
!  Easiest thing is to only let month and year be decremented by themselves
!  This is slight overkill since year is not really a problem.
	if(months /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     &         .or. hours /= 0 .or.  days /= 0 .or. years /= 0)) 
     &   call error_handler ('decrement_julian: month must not '//
     &   'be decremented with other units')
	if(years /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     &   .or. hours /= 0 .or. days /= 0 .or. months /= 0)) 
     & call error_handler ('decrement_julian: year must not '//
     &   'be decremented with other units')
!  For non-month and non-year can just use decrement_thirty
	t = decrement_thirty(time, 0, 0, days, hours, 
     &                       minutes, seconds)
!  For month or year decrement, first convert to date
	call get_date_julian(t, cyear, cmonth, cday, chour, 
     &                       cminute, csecond)
	cmonth = cmonth - months
	cyear = cyear - years
! Check for months less than 12 and fix
	if(cmonth < 1) then
	   cyear = cyear - 1 + (cmonth) / 12
	   cmonth = cmonth - 12 * ( -1 + (cmonth) / 12)
	end if
! Check for negative years
	if(cyear < 1) 
     &   call error_handler('Illegal date results in decrement_julian')
! Convert this back into a time
	decrement_julian = set_date_julian(cyear, cmonth, cday, 
     &                  chour, cminute, csecond)
	end function decrement_julian
!-------------------------------------------------------------------------
	function decrement_thirty(time, years, months, days, 
     &                            hours, minutes, seconds)
! Given a time and some date decrement, computes new time for thirty day months.
	implicit none
	type(time_type) :: decrement_thirty,time2
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, minutes, 
     &                         hours, days, months, years
	integer :: csecond, cday
! Increment must be positive definite
	if(seconds < 0 .or. minutes < 0 .or. hours < 0 
     &    .or. days < 0 .or. months < 0 .or. years < 0) 
     &	  call error_handler('Illegal decrement in decrement_thirty')
	csecond = seconds + 60 * (minutes + 60 * hours)
	cday = days + 30 * (months + 12 * years)
c	decrement_thirty = decrement_time(time, csecond, cday)
	call decrement_time(time2 ,time, csecond, cday)
	decrement_thirty =time2
	end function decrement_thirty
!-------------------------------------------------------------------------
	function decrement_no_leap(time, years, months, days, 
     &                             hours, minutes, seconds)
! Given time and some date decrement, computes new time for julian calendar.
	implicit none
	type(time_type) :: decrement_no_leap
	type(time_type), intent(in) :: time
	integer, intent(in) :: seconds, minutes, 
     &                                   hours, days, months, years
	integer :: csecond, cminute, chour, cday, cmonth, cyear
	type(time_type) :: t
! Increment must be positive definite
	if(seconds < 0 .or. minutes < 0 .or. hours < 0 
     &    .or. days < 0 .or. months < 0 .or. years < 0) 
     &	   call error_handler('Illegal increment in decrement_no_leap')
!  There are a number of other bad types of decrements that should be
!  prohibited here; the subtraction is not associative
!  Easiest thing is to only let month and year be decremented by themselves
!  This is slight overkill since year is not really a problem.
	if(months /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     &      .or. hours /= 0 .or. days /= 0 .or. years /= 0)) 
     &    call error_handler('decrement_no_leap: month must not '//
     &  'be decremented with other units')
	if(years /= 0 .and. (seconds /= 0 .or. minutes /= 0 
     & .or. hours /= 0 .or. days /= 0 .or. months /= 0)) 
     &   call error_handler('decrement_no_leap: year must not '//
     &  'be decremented with other units')
!  For non-month and non-year can just use decrement_thirty
	t = decrement_thirty(time, 0, 0, days, hours, 
     &                       minutes, seconds)
!  For month or year decrement, first convert to date
	call get_date_no_leap(t, cyear, cmonth, cday, chour, 
     &                        cminute, csecond)
	cmonth = cmonth - months
	cyear = cyear - years
! Check for months less than 12 and fix
	if(cmonth < 1) then
	   cyear = cyear - 1 + (cmonth) / 12
	   cmonth = cmonth - 12 * ( -1 + (cmonth) / 12)
	end if
! Check for negative years
	if(cyear < 1) call 
     &        error_handler('Illegal date results in decrement_no_leap')
! Convert this back into a time
	decrement_no_leap = set_date_no_leap(cyear, cmonth, cday, 
     &   chour, cminute, csecond)
	end function decrement_no_leap

	subroutine error_handler(s)
	implicit none
	character (*), intent(in) :: s
c	write(*, *) 'ERROR: In time_type_mod: ', s
	call halt_stop('ERROR: In time_type_mod: '//s)

	end subroutine error_handler


	end module time_type_module





