2 ! Author(s)/Contact(s):
7 ! Parameters: <Specify typical arguments passed>
9 ! <list file names and briefly describe the data they include>
11 ! <list file names and briefly describe the information they include>
14 ! <list exit condition or error codes returned >
15 ! If appropriate, descriptive troubleshooting instructions or
16 ! likely causes for failures could be mentioned here with the
17 ! appropriate error code
19 ! User controllable options: <if applicable>
21 module Module_Date_utilities_rt
22 use module_hydro_stop, only: HYDRO_stop
24 subroutine geth_newdate (ndate, odate, idt)
27 ! From old date ("YYYY-MM-DD HH:MM:SS.ffff" or "YYYYMMDDHHMMSSffff") and
28 ! delta-time, compute the new date.
30 ! on entry - odate - the old hdate.
31 ! idt - the change in time
33 ! on exit - ndate - the new hdate.
35 integer, intent(in) :: idt
36 character (len=*), intent(out) :: ndate
37 character (len=*), intent(in) :: odate
41 ! yrold - indicates the year associated with "odate"
42 ! moold - indicates the month associated with "odate"
43 ! dyold - indicates the day associated with "odate"
44 ! hrold - indicates the hour associated with "odate"
45 ! miold - indicates the minute associated with "odate"
46 ! scold - indicates the second associated with "odate"
48 ! yrnew - indicates the year associated with "ndate"
49 ! monew - indicates the month associated with "ndate"
50 ! dynew - indicates the day associated with "ndate"
51 ! hrnew - indicates the hour associated with "ndate"
52 ! minew - indicates the minute associated with "ndate"
53 ! scnew - indicates the second associated with "ndate"
55 ! mday - a list assigning the number of days in each month
58 ! nday - the integer number of days represented by "idt"
59 ! nhour - the integer number of hours in "idt" after taking out
61 ! nmin - the integer number of minutes in "idt" after taking out
62 ! all the whole days and whole hours.
63 ! nsec - the integer number of minutes in "idt" after taking out
64 ! all the whole days, whole hours, and whole minutes.
66 integer :: newlen, oldlen
67 integer :: yrnew, monew, dynew, hrnew, minew, scnew, frnew
68 integer :: yrold, moold, dyold, hrold, miold, scold, frold
69 integer :: nday, nhour, nmin, nsec, nfrac, i, ifrc
71 character (len=10) :: hfrc
72 character (len=1) :: sp
74 integer :: yrstart, yrend, mostart, moend, dystart, dyend
75 integer :: hrstart, hrend, mistart, miend, scstart, scend, frstart
77 integer, dimension(12) :: mday = (/31,28,31,30,31,30,31,31,30,31,30,31/)
79 ! Determine if odate is "YYYY-MM-DD_HH ... " or "YYYYMMDDHH...."
80 if (odate(5:5) == "-") then
86 ! Break down old hdate into parts
133 write(*,*) 'ERROR: geth_newdate: odd length: #'//trim(odate)//'#'
134 call hydro_stop("In geth_newdate() odd length")
137 if (oldlen.ge.11) then
185 write(*,*) 'ERROR: geth_newdate: odd length: #'//trim(odate)//'#'
186 call hydro_stop("In geth_newdate() - odd length")
190 ! Use internal READ statements to convert the CHARACTER string
191 ! date into INTEGER components.
193 read(odate(yrstart:yrend), '(i4)') yrold
194 read(odate(mostart:moend), '(i2)') moold
195 read(odate(dystart:dyend), '(i2)') dyold
197 read(odate(hrstart:hrend),'(i2)') hrold
199 read(odate(mistart:miend),'(i2)') miold
201 read(odate(scstart:scend),'(i2)') scold
203 read(odate(frstart:oldlen),*) frold
209 ! Set the number of days in February for that year.
211 mday(2) = nfeb(yrold)
213 ! Check that ODATE makes sense.
217 ! Check that the month of ODATE makes sense.
219 if ((moold.gt.12).or.(moold.lt.1)) then
221 write(*,*) 'GETH_NEWDATE: Month of ODATE = ', moold
226 ! Check that the day of ODATE makes sense.
228 if ((dyold.gt.mday(moold)).or.(dyold.lt.1)) then
230 write(*,*) 'GETH_NEWDATE: Day of ODATE = ', dyold
235 ! Check that the hour of ODATE makes sense.
237 if ((hrold.gt.23).or.(hrold.lt.0)) then
239 write(*,*) 'GETH_NEWDATE: Hour of ODATE = ', hrold
244 ! Check that the minute of ODATE makes sense.
246 if ((miold.gt.59).or.(miold.lt.0)) then
248 write(*,*) 'GETH_NEWDATE: Minute of ODATE = ', miold
253 ! Check that the second of ODATE makes sense.
255 if ((scold.gt.59).or.(scold.lt.0)) then
257 write(*,*) 'GETH_NEWDATE: Second of ODATE = ', scold
262 ! Check that the fractional part of ODATE makes sense.
267 write(*,*) 'Crazy ODATE: ', odate(1:oldlen), oldlen
268 call hydro_stop("In geth_newdate() - Crazy ODATE")
272 ! Date Checks are completed. Continue.
275 ! Compute the number of days, hours, minutes, and seconds in idt
277 if (units.ge.5) then !idt should be in fractions of seconds
278 ifrc = oldlen-(frstart)+1
280 nday = abs(idt)/(86400*ifrc)
281 nhour = mod(abs(idt),86400*ifrc)/(3600*ifrc)
282 nmin = mod(abs(idt),3600*ifrc)/(60*ifrc)
283 nsec = mod(abs(idt),60*ifrc)/(ifrc)
284 nfrac = mod(abs(idt), ifrc)
285 else if (units.eq.4) then !idt should be in seconds
287 nday = abs(idt)/86400 ! integer number of days in delta-time
288 nhour = mod(abs(idt),86400)/3600
289 nmin = mod(abs(idt),3600)/60
290 nsec = mod(abs(idt),60)
292 else if (units.eq.3) then !idt should be in minutes
294 nday = abs(idt)/1440 ! integer number of days in delta-time
295 nhour = mod(abs(idt),1440)/60
296 nmin = mod(abs(idt),60)
299 else if (units.eq.2) then !idt should be in hours
301 nday = abs(idt)/24 ! integer number of days in delta-time
302 nhour = mod(abs(idt),24)
306 else if (units.eq.1) then !idt should be in days
308 nday = abs(idt) ! integer number of days in delta-time
314 write(*,'(''GETH_NEWDATE: Strange length for ODATE: '', i3)') &
316 write(*,*) '#'//odate(1:oldlen)//'#'
317 call hydro_stop("In geth_newdate()")
322 frnew = frold + nfrac
323 if (frnew.ge.ifrc) then
329 if (scnew .ge. 60) then
335 if (minew .ge. 60) then
340 hrnew = hrold + nhour
341 if (hrnew .ge. 24) then
351 if (dynew.gt.mday(monew)) then
352 dynew = dynew - mday(monew)
354 if (monew .gt. 12) then
357 ! If the year changes, recompute the number of days in February
358 mday(2) = nfeb(yrnew)
363 else if (idt.lt.0) then
365 frnew = frold - nfrac
366 if (frnew .lt. 0) then
372 if (scnew .lt. 00) then
378 if (minew .lt. 00) then
383 hrnew = hrold - nhour
384 if (hrnew .lt. 00) then
399 ! If the year changes, recompute the number of days in February
400 mday(2) = nfeb(yrnew)
407 ! Now construct the new mdate
413 if (newlen.gt.frstart) then
414 write(ndate(1:scend),19) yrnew, monew, dynew, hrnew, minew, scnew
415 write(hfrc,'(i10)') frnew+1000000000
416 ndate = ndate(1:scend)//'.'//hfrc(31-newlen:10)
418 else if (newlen.eq.scend) then
419 write(ndate(1:scend),19) yrnew, monew, dynew, hrnew, minew, scnew
420 19 format(i4,'-',i2.2,'-',i2.2,'_',i2.2,':',i2.2,':',i2.2)
422 else if (newlen.eq.miend) then
423 write(ndate,16) yrnew, monew, dynew, hrnew, minew
424 16 format(i4,'-',i2.2,'-',i2.2,'_',i2.2,':',i2.2)
426 else if (newlen.eq.hrend) then
427 write(ndate,13) yrnew, monew, dynew, hrnew
428 13 format(i4,'-',i2.2,'-',i2.2,'_',i2.2)
430 else if (newlen.eq.dyend) then
431 write(ndate,10) yrnew, monew, dynew
432 10 format(i4,'-',i2.2,'-',i2.2)
438 if (newlen.gt.frstart) then
439 write(ndate(1:scend),119) yrnew, monew, dynew, hrnew, minew, scnew
440 write(hfrc,'(i10)') frnew+1000000000
441 ndate = ndate(1:scend)//'.'//hfrc(31-newlen:10)
443 else if (newlen.eq.scend) then
444 write(ndate(1:scend),119) yrnew, monew, dynew, hrnew, minew, scnew
445 119 format(i4,i2.2,i2.2,i2.2,i2.2,i2.2)
447 else if (newlen.eq.miend) then
448 write(ndate,116) yrnew, monew, dynew, hrnew, minew
449 116 format(i4,i2.2,i2.2,i2.2,i2.2)
451 else if (newlen.eq.hrend) then
452 write(ndate,113) yrnew, monew, dynew, hrnew
453 113 format(i4,i2.2,i2.2,i2.2)
455 else if (newlen.eq.dyend) then
456 write(ndate,110) yrnew, monew, dynew
457 110 format(i4,i2.2,i2.2)
463 if (punct .and. (oldlen.ge.11) .and. (newlen.ge.11)) ndate(11:11) = sp
465 end subroutine geth_newdate
467 subroutine geth_idts (newdate, olddate, idt)
470 ! From 2 input mdates ('YYYY-MM-DD HH:MM:SS.ffff'),
471 ! compute the time difference.
473 ! on entry - newdate - the new hdate.
474 ! olddate - the old hdate.
476 ! on exit - idt - the change in time.
477 ! Units depend on length of date strings.
479 character (len=*) , intent(in) :: newdate, olddate
480 integer , intent(out) :: idt
485 ! yrnew - indicates the year associated with "ndate"
486 ! yrold - indicates the year associated with "odate"
487 ! monew - indicates the month associated with "ndate"
488 ! moold - indicates the month associated with "odate"
489 ! dynew - indicates the day associated with "ndate"
490 ! dyold - indicates the day associated with "odate"
491 ! hrnew - indicates the hour associated with "ndate"
492 ! hrold - indicates the hour associated with "odate"
493 ! minew - indicates the minute associated with "ndate"
494 ! miold - indicates the minute associated with "odate"
495 ! scnew - indicates the second associated with "ndate"
496 ! scold - indicates the second associated with "odate"
498 ! mday - a list assigning the number of days in each month
500 ! ndate, odate: local values of newdate and olddate
501 character(len=24) :: ndate, odate
503 integer :: oldlen, newlen
504 integer :: yrnew, monew, dynew, hrnew, minew, scnew, frnew
505 integer :: yrold, moold, dyold, hrold, miold, scold, frold
506 integer :: i, newdys, olddys
507 logical :: npass, opass
510 integer, dimension(12) :: mday = (/31,28,31,30,31,30,31,31,30,31,30,31/)
512 integer :: yrstart, yrend, mostart, moend, dystart, dyend
513 integer :: hrstart, hrend, mistart, miend, scstart, scend, frstart
516 oldlen = len(olddate)
517 newlen = len(newdate)
518 if (newlen.ne.oldlen) then
519 write(*,'("GETH_IDTS: NEWLEN /= OLDLEN: ", A, 3x, A)') newdate(1:newlen), olddate(1:oldlen)
520 call hydro_stop("In geth_idts() - NEWLEN /= OLDLEN")
523 if (olddate.gt.newdate) then
538 ! Break down old hdate into parts
540 ! Determine if olddate is punctuated or not
541 if (odate(5:5) == "-") then
543 if (ndate(5:5) /= "-") then
544 write(*,'("GETH_IDTS: Dates appear to be different formats: ", A, 3x, A)') &
545 ndate(1:newlen), odate(1:oldlen)
546 call hydro_stop("In geth_idts() - Dates appear to be different formats")
550 if (ndate(5:5) == "-") then
551 write(*,'("GETH_IDTS: Dates appear to be different formats: ", A, 3x, A)') &
552 ndate(1:newlen), odate(1:oldlen)
553 call hydro_stop("In geth_idts() - Dates appear to be different formats")
597 write(*,*) 'ERROR: geth_idts: odd length: #'//trim(odate)//'#'
598 call hydro_stop("In geth_idts() - odd length")
642 write(*,*) 'ERROR: geth_idts: odd length: #'//trim(odate)//'#'
643 call hydro_stop("In geth_idts() - odd length")
653 read(odate(yrstart:yrend), '(i4)') yrold
654 read(odate(mostart:moend), '(i2)') moold
655 read(odate(dystart:dyend), '(i2)') dyold
657 read(odate(hrstart:hrend),'(i2)') hrold
659 read(odate(mistart:miend),'(i2)') miold
661 read(odate(scstart:scend),'(i2)') scold
663 read(odate(frstart:oldlen),*) frold
669 ! Break down new hdate into parts
676 read(ndate(yrstart:yrend), '(i4)') yrnew
677 read(ndate(mostart:moend), '(i2)') monew
678 read(ndate(dystart:dyend), '(i2)') dynew
680 read(ndate(hrstart:hrend),'(i2)') hrnew
682 read(ndate(mistart:miend),'(i2)') minew
684 read(ndate(scstart:scend),'(i2)') scnew
686 read(ndate(frstart:newlen),*) frnew
692 ! Check that the dates make sense.
697 ! Check that the month of NDATE makes sense.
699 if ((monew.gt.12).or.(monew.lt.1)) then
701 write(*,*) 'GETH_IDTS: Month of NDATE = ', monew
706 ! Check that the month of ODATE makes sense.
708 if ((moold.gt.12).or.(moold.lt.1)) then
710 print*, 'GETH_IDTS: Month of ODATE = ', moold
715 ! Check that the day of NDATE makes sense.
718 ! ...... For all months but February
719 if ((dynew.gt.mday(monew)).or.(dynew.lt.1)) then
721 print*, 'GETH_IDTS: Day of NDATE = ', dynew
725 else if (monew.eq.2) then
726 ! ...... For February
727 if ((dynew > nfeb(yrnew)).or.(dynew < 1)) then
729 print*, 'GETH_IDTS: Day of NDATE = ', dynew
735 ! Check that the day of ODATE makes sense.
738 ! ...... For all months but February
739 if ((dyold.gt.mday(moold)).or.(dyold.lt.1)) then
741 print*, 'GETH_IDTS: Day of ODATE = ', dyold
745 else if (moold.eq.2) then
746 ! ....... For February
747 if ((dyold > nfeb(yrold)).or.(dyold < 1)) then
749 print*, 'GETH_IDTS: Day of ODATE = ', dyold
755 ! Check that the hour of NDATE makes sense.
757 if ((hrnew.gt.23).or.(hrnew.lt.0)) then
759 print*, 'GETH_IDTS: Hour of NDATE = ', hrnew
764 ! Check that the hour of ODATE makes sense.
766 if ((hrold.gt.23).or.(hrold.lt.0)) then
768 print*, 'GETH_IDTS: Hour of ODATE = ', hrold
773 ! Check that the minute of NDATE makes sense.
775 if ((minew.gt.59).or.(minew.lt.0)) then
777 print*, 'GETH_IDTS: Minute of NDATE = ', minew
782 ! Check that the minute of ODATE makes sense.
784 if ((miold.gt.59).or.(miold.lt.0)) then
786 print*, 'GETH_IDTS: Minute of ODATE = ', miold
791 ! Check that the second of NDATE makes sense.
793 if ((scnew.gt.59).or.(scnew.lt.0)) then
795 print*, 'GETH_IDTS: SECOND of NDATE = ', scnew
800 ! Check that the second of ODATE makes sense.
802 if ((scold.gt.59).or.(scold.lt.0)) then
804 print*, 'GETH_IDTS: Second of ODATE = ', scold
809 if (.not. npass) then
810 print*, 'Screwy NDATE: ', ndate(1:newlen)
811 call hydro_stop("In geth_idts() - Screwy NDATE ")
814 if (.not. opass) then
815 print*, 'Screwy ODATE: ', odate(1:oldlen)
816 call hydro_stop("In geth_idts() - Screwy ODATE ")
819 ! Date Checks are completed. Continue.
821 ! Compute number of days from 1 January ODATE, 00:00:00 until ndate
822 ! Compute number of hours from 1 January ODATE, 00:00:00 until ndate
823 ! Compute number of minutes from 1 January ODATE, 00:00:00 until ndate
826 do i = yrold, yrnew - 1
827 newdys = newdys + 337 + nfeb(i)
830 if (monew .gt. 1) then
831 mday(2) = nfeb(yrnew)
833 newdys = newdys + mday(i)
838 newdys = newdys + dynew - 1
840 ! Compute number of hours from 1 January ODATE, 00:00:00 until odate
841 ! Compute number of minutes from 1 January ODATE, 00:00:00 until odate
845 if (moold .gt. 1) then
846 mday(2) = nfeb(yrold)
848 olddys = olddys + mday(i)
853 olddys = olddys + dyold -1
855 ! Determine the time difference
857 idt = (newdys - olddys)
859 idt = idt*24 + (hrnew - hrold)
861 idt = idt*60 + (minew - miold)
863 idt = idt*60 + (scnew - scold)
865 ifrc = oldlen-(frstart-1)
867 idt = idt * ifrc + (frnew-frold)
873 if (timesign .eq. -1) then
877 end subroutine geth_idts
880 integer function nfeb(year)
882 ! Compute the number of days in February for the given year.
885 integer, intent(in) :: year ! Four-digit year
887 nfeb = 28 ! By default, February has 28 days ...
888 if (mod(year,4).eq.0) then
889 nfeb = 29 ! But every four years, it has 29 days ...
890 if (mod(year,100).eq.0) then
891 nfeb = 28 ! Except every 100 years, when it has 28 days ...
892 if (mod(year,400).eq.0) then
893 nfeb = 29 ! Except every 400 years, when it has 29 days ...
894 if (mod(year,3600).eq.0) then
895 nfeb = 28 ! Except every 3600 years, when it has 28 days.
902 integer function nmdays(hdate)
904 ! Compute the number of days in the month of given date hdate.
907 character(len=*), intent(in) :: hdate
909 integer :: year, month
910 integer, dimension(12), parameter :: ndays = (/ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 /)
912 read(hdate(1:7), '(I4,1x,I2)') year, month
917 nmdays = ndays(month)
921 function monthabbr_to_mm(mon) result(mm)
924 character(len=3), intent(in) :: mon
928 if (mon == "Jan") then
930 elseif (mon == "Feb") then
932 elseif (mon == "Mar") then
934 elseif (mon == "Apr") then
936 elseif (mon == "May") then
938 elseif (mon == "Jun") then
940 elseif (mon == "Jul") then
942 elseif (mon == "Aug") then
944 elseif (mon == "Sep") then
946 elseif (mon == "Oct") then
948 elseif (mon == "Nov") then
950 elseif (mon == "Dec") then
953 write(*, '("Function monthabbr_to_mm: mon = <",A,">")') mon
954 print*, "Function monthabbr_to_mm: Unrecognized mon"
955 call hydro_stop("In monthabbr_to_mm() - Unrecognized mon")
957 end function monthabbr_to_mm
959 subroutine swap_date_format(indate, outdate)
961 character(len=*), intent(in) :: indate
962 character(len=*), intent(out) :: outdate
966 if (indate(5:5) == "-") then
970 outdate = indate(1:4)//indate(6:7)//indate(9:10)
973 outdate = indate(1:4)//indate(6:7)//indate(9:10)//indate(12:13)
976 outdate = indate(1:4)//indate(6:7)//indate(9:10)//indate(12:13)//indate(15:16)
978 ! YYYY-MM-DD_HH:mm:ss
979 outdate = indate(1:4)//indate(6:7)//indate(9:10)//indate(12:13)//indate(15:16)//&
982 ! YYYY-MM-DD_HH:mm:ss.f[f[f[f]]]
983 outdate = indate(1:4)//indate(6:7)//indate(9:10)//indate(12:13)//indate(15:16)//&
984 indate(18:19)//indate(21:inlen)
986 write(*,'("Unrecognized length: <", A,">")') indate
987 call hydro_stop("In swap_date_format() - Unrecognized length")
993 outdate = indate(1:4)//"-"//indate(5:6)//"-"//indate(7:8)
996 outdate = indate(1:4)//"-"//indate(5:6)//"-"//indate(7:8)//"_"//&
1000 outdate = indate(1:4)//"-"//indate(5:6)//"-"//indate(7:8)//"_"//&
1001 indate(9:10)//":"//indate(11:12)
1004 outdate = indate(1:4)//"-"//indate(5:6)//"-"//indate(7:8)//"_"//&
1005 indate(9:10)//":"//indate(11:12)//":"//indate(13:14)
1007 ! YYYYMMDDHHmmssf[f[f[f]]]
1008 outdate = indate(1:4)//"-"//indate(5:6)//"-"//indate(7:8)//"_"//&
1009 indate(9:10)//":"//indate(11:12)//":"//indate(13:14)//"."//indate(15:inlen)
1011 write(*,'("Unrecognized length: <", A,">")') indate
1012 call hydro_stop("In swap_date_format() - Unrecognized length")
1016 end subroutine swap_date_format
1018 character(len=3) function mm_to_monthabbr(ii) result(mon)
1020 integer, intent(in) :: ii
1021 character(len=3), parameter, dimension(12) :: month = (/ &
1022 "Jan", "Feb", "Mar", "Apr", "May", "Jun", &
1023 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" /)
1024 if (ii > 0 .and. ii < 13 ) then
1027 ! print*, "mm_to_monthabbr"
1028 call hydro_stop("In mm_to_monthabbr() - mm_to_monthabbr")
1030 end function mm_to_monthabbr
1032 end module Module_Date_utilities_rt