26 module get_cal_time_mod
33 no_calendar, thirty_day_months, noleap, julian, gregorian, &
36 use mpp_mod,
only: input_nml_file
37 use platform_mod,
only: r8_kind, r4_kind
44 logical :: module_is_initialized=.false.
55 logical :: allow_calendar_conversion=.true.
57 namelist / get_cal_time_nml / allow_calendar_conversion
61 #include<file_version.h>
163 real(r8_kind),
intent(in) :: time_increment
164 character(len=*),
intent(in) :: units
165 character(len=*),
intent(in) :: calendar
166 logical,
intent(in),
optional :: permit_calendar_conversion
168 integer :: year, month, day, hour, minute, second
169 integer :: i1, increment_seconds, increment_days, increment_years, increment_months
170 real(r8_kind) :: month_fraction
171 integer :: calendar_tm_i, calendar_in_i, ierr, io, logunit
172 logical :: correct_form
173 character(len=32) :: calendar_in_c
174 character(len=64) :: err_msg
175 type(
time_type) :: base_time, base_time_plus_one_yr
177 logical :: permit_conversion_local
178 integer,
parameter :: spd_int = 86400
179 real(r8_kind),
parameter :: spd_real = 86400.0_r8_kind
181 if(.not.module_is_initialized)
then
182 read (input_nml_file, get_cal_time_nml, iostat=io)
187 if(
mpp_pe() == mpp_root_pe())
write (logunit, nml=get_cal_time_nml)
188 module_is_initialized = .true.
191 if(
present(permit_calendar_conversion))
then
192 permit_conversion_local = permit_calendar_conversion
194 permit_conversion_local = allow_calendar_conversion
197 calendar_in_c = lowercase(trim(cut0(calendar)))
199 correct_form = (trim(calendar_in_c)) ==
'noleap' .or. (trim(calendar_in_c)) ==
'365_day' .or. &
200 (trim(calendar_in_c)) ==
'365_days' .or. &
201 (trim(calendar_in_c)) ==
'360_day' .or. (trim(calendar_in_c)) ==
'julian' .or. &
202 (trim(calendar_in_c)) ==
'no_calendar'.or. (trim(calendar_in_c)) ==
'thirty_day_months' .or. &
203 (trim(calendar_in_c)) ==
'gregorian'
205 if(.not.correct_form)
then
206 call error_mesg(
'get_calendar_time',
'"'//trim(calendar_in_c)//
'"'// &
207 ' is not an acceptable calendar attribute. acceptable calendars are: '// &
208 ' noleap, 365_day, 365_days, 360_day, julian, no_calendar, thirty_day_months, gregorian',fatal)
213 if(.not.permit_conversion_local)
then
214 correct_form = (trim(calendar_in_c) ==
'noleap' .and. calendar_tm_i == noleap) .or. &
215 (trim(calendar_in_c) ==
'365_day' .and. calendar_tm_i == noleap) .or. &
216 (trim(calendar_in_c) ==
'365_days' .and. calendar_tm_i == noleap) .or. &
217 (trim(calendar_in_c) ==
'360_day' .and. calendar_tm_i == thirty_day_months) .or. &
218 (trim(calendar_in_c) ==
'thirty_day_months' .and. calendar_tm_i == thirty_day_months) .or. &
219 (trim(calendar_in_c) ==
'julian' .and. calendar_tm_i == julian) .or. &
220 (trim(calendar_in_c) ==
'no_calendar' .and. calendar_tm_i == no_calendar) .or. &
221 (trim(calendar_in_c) ==
'gregorian' .and. calendar_tm_i == gregorian)
222 if(.not.correct_form)
then
223 call error_mesg(
'get_calendar_time',
'calendar not consistent with calendar type in use by time_manager.'// &
224 ' calendar='//trim(calendar_in_c)//
'. Type in use by time_manager='// &
229 if (permit_conversion_local)
then
230 select case (trim(calendar_in_c))
232 calendar_in_i = noleap
234 calendar_in_i = noleap
236 calendar_in_i = noleap
238 calendar_in_i = thirty_day_months
239 case (
'thirty_day_months')
240 calendar_in_i = thirty_day_months
242 calendar_in_i = julian
244 calendar_in_i = no_calendar
246 calendar_in_i = gregorian
249 trim(calendar_in_c)//
' is an invalid calendar type (specified in call to get_calendar_time)',fatal)
252 calendar_in_i = calendar_tm_i
255 correct_form = lowercase(units(1:10)) ==
'days since' .or. &
256 lowercase(units(1:11)) ==
'hours since' .or. &
257 lowercase(units(1:13)) ==
'minutes since' .or. &
258 lowercase(units(1:13)) ==
'seconds since'
260 if(calendar_in_i /= no_calendar)
then
261 correct_form = correct_form .or. &
262 lowercase(units(1:11)) ==
'years since' .or. &
263 lowercase(units(1:12)) ==
'months since'
266 if(.not.correct_form)
then
267 call error_mesg(
'get_calendar_time',trim(units)//
' is an invalid string for units.' // &
268 ' units must begin with a time unit then the word "since"' // &
269 ' Valid time units are: "seconds" "minutes", "hours", "days", and, ' // &
270 ' except when NO_CALENDAR is in effect, "months" and "years"',fatal)
273 if(calendar_in_i /= calendar_tm_i)
then
287 i1 = index(units,
'since') + 5
288 if(calendar_in_i == no_calendar)
then
289 base_time =
set_time(units(i1:len_trim(units)))
291 base_time =
set_date(units(i1:len_trim(units)))
294 if(lowercase(units(1:10)) ==
'days since')
then
295 increment_days = floor(time_increment)
296 increment_seconds = int(spd_real*(time_increment - real(increment_days, r8_kind)))
297 else if(lowercase(units(1:11)) ==
'hours since')
then
298 increment_days = floor(time_increment/24.0_r8_kind)
299 increment_seconds = int(spd_real*(time_increment/24.0_r8_kind - real(increment_days, r8_kind)))
300 else if(lowercase(units(1:13)) ==
'minutes since')
then
301 increment_days = floor(time_increment/1440.0_r8_kind)
302 increment_seconds = int(spd_real*(time_increment/1440.0_r8_kind - real(increment_days, r8_kind)))
303 else if(lowercase(units(1:13)) ==
'seconds since')
then
304 increment_days = floor(time_increment/spd_real)
305 increment_seconds = int(spd_real*(time_increment/spd_real - real(increment_days, r8_kind)))
306 else if(lowercase(units(1:11)) ==
'years since')
then
310 call get_date(base_time, year,month,day,hour,minute,second)
311 base_time =
set_date(year+floor(time_increment) ,month,day,hour,minute,second)
312 base_time_plus_one_yr =
set_date(year+floor(time_increment)+1,month,day,hour,minute,second)
313 call get_time(base_time_plus_one_yr - base_time, second, day)
314 dt = real(day*spd_int+second, r8_kind)*(time_increment-real(floor(time_increment), r8_kind))
315 increment_days = floor(dt/spd_real)
316 increment_seconds = int(dt - real(increment_days*spd_int, r8_kind))
317 else if(lowercase(units(1:12)) ==
'months since')
then
318 month_fraction = time_increment - real(floor(time_increment), r8_kind)
319 increment_years = floor(time_increment/12.0_r8_kind)
320 increment_months = floor(time_increment) - 12*increment_years
321 call get_date(base_time, year,month,day,hour,minute,second)
322 base_time =
set_date(year+increment_years,month+increment_months ,day,hour,minute,second)
323 dt = real( spd_int*
days_in_month(base_time), r8_kind) * month_fraction
324 increment_days = floor(dt/spd_real)
325 increment_seconds = int(dt - real(increment_days, r8_kind)*spd_real)
327 call error_mesg(
'get_calendar_time',
'"'//trim(units)//
'" is not an acceptable units attribute of time.'// &
328 &
' It must begin with: "years since", "months since", "days since", "hours since", "minutes since",'// &
329 &
' or "seconds since"',fatal)
332 if (calendar_in_i /= calendar_tm_i)
then
333 if(calendar_in_i == no_calendar .or. calendar_tm_i == no_calendar)
then
334 call error_mesg(
'get_calendar_time',
'Cannot do calendar conversion because input calendar is '// &
337 ' Conversion cannot be done if either is NO_CALENDAR',fatal)
339 call get_date(base_time,year, month, day, hour, minute, second)
344 if(err_msg /=
'')
then
345 call error_mesg(
'get_calendar_time',
'Error in function get_calendar_time: '//trim(err_msg)// &
346 ' Note that the time_manager is using the '//trim(
valid_calendar_types(calendar_tm_i))//
' calendar '// &
347 'while the calendar type passed to function get_calendar_time is '//calendar_in_c,fatal)
359 real(r4_kind),
intent(in) :: time_increment
360 character(len=*),
intent(in) :: units
361 character(len=*),
intent(in) :: calendar
362 logical,
intent(in),
optional :: permit_calendar_conversion
366 permit_calendar_conversion=permit_calendar_conversion)
371 function cut0(string)
372 character(len=256) :: cut0
373 character(len=*),
intent(in) :: string
379 if(ichar(string(i:i)) == 0 )
then
387 end module get_cal_time_mod
integer function, public check_nml_error(IOSTAT, NML_NAME)
Checks the iostat argument that is returned after reading a namelist and determines if the error code...
subroutine, public write_version_number(version, tag, unit)
Prints to the log file (or a specified unit) the version id string and tag name.
subroutine, public error_mesg(routine, message, level)
Print notes, warnings and error messages; terminates program for warning and error messages....
type(time_type) function get_calendar_time(time_increment, units, calendar, permit_calendar_conversion)
Calculates what a given calendar time would be after a interval of time.
type(time_type) function get_calendar_time_wrap(time_increment, units, calendar, permit_calendar_conversion)
For mixed precision support, just casts to passed in increment to r8.
Added for mixed precision support. Updates force time_manager math to be done with kind=8 reals _wrap...
integer function stdlog()
This function returns the current standard fortran unit numbers for log messages. Log messages,...
integer function mpp_pe()
Returns processor ID.
subroutine, public get_time(Time, seconds, days, ticks, err_msg)
Returns days and seconds ( < 86400 ) corresponding to a time. err_msg should be checked for any error...
character(len=24) function, public valid_calendar_types(ncal, err_msg)
Returns a character string that describes the calendar type corresponding to the input integer.
subroutine, public get_date(time, year, month, day, hour, minute, second, tick, err_msg)
Gets the date for different calendar types. Given a time_interval, returns the corresponding date und...
integer function, public days_in_month(Time, err_msg)
Given a time, computes the corresponding date given the selected date time mapping algorithm.
integer function, public get_calendar_type()
Returns default calendar type for mapping from time to date.
subroutine, public set_calendar_type(type, err_msg)
Sets calendar_type for mapping an interval to a date. For the Gregorian calendar, negative years and ...
Given an input date in year, month, days, etc., creates a time_type that represents this time interva...
Given some number of seconds and days, returns the corresponding time_type.
Type to represent amounts of time. Implemented as seconds and days to allow for larger intervals.