datetime.F90 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. !#################################################################
  2. !
  3. !* module contains all routines that deal with date/time calculation *
  4. !
  5. ! subroutine chardate(idate6,cdate)
  6. ! subroutine inctime
  7. ! subroutine tau2date(itaux,idatex)
  8. ! subroutine date2tau(idatex,itaux)
  9. ! subroutine calc_sm( mlen, sec_day, sec_month, sec_year )
  10. ! subroutine dayl(day,daylen,jdim,lat_start,dlat)
  11. ! subroutine caldat(julian,mm,id,iyyy)
  12. ! integer function julday(mm,id,iy)
  13. ! integer function get_day(mm,dd,mlen)
  14. ! subroutine tstamp(kunit,itaux,msg)
  15. !
  16. !### macro's #####################################################
  17. !
  18. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  19. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  20. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  21. !
  22. #include "tm5.inc"
  23. !
  24. !#################################################################
  25. module datetime
  26. use GO, only : gol, goErr, goPr
  27. implicit none
  28. ! --- in/out -------------------------------------
  29. private
  30. public :: inctime, tau2date, date2tau, dayl, idate2ddate
  31. public :: get_day, julday, calc_sm, new_valid_timestep
  32. public :: tstamp, wrtgol_tstamp, chardate
  33. contains
  34. ! ==============================================================
  35. !-----------------------------------------------------------------------
  36. !
  37. ! put date/time in character string
  38. !
  39. ! on input: idate6 contains date/time
  40. ! on output: cdata contains date/time string
  41. !
  42. !-----------------------------------------------------------------------
  43. subroutine chardate(idate6,cdate)
  44. integer,dimension(6),intent(in) :: idate6 ! "chardate" input date
  45. character(24) :: cdate ! "chardate" output string
  46. !
  47. integer :: k
  48. character(3),dimension(12),parameter :: mon= &
  49. (/'jan','feb','mar','apr','may','jun', &
  50. 'jul','aug','sep','oct','nov','dec'/)
  51. !
  52. ! put date/time in string
  53. !
  54. write(cdate,'(i4,"-",a3,"-",i2," ",i2,":",i2,":",i2," ")') &
  55. idate6(1),mon(idate6(2)),(idate6(k),k=3,6)
  56. !
  57. end subroutine chardate
  58. !-----------------------------------------------------------------------
  59. !**** inctime
  60. !
  61. ! purpose
  62. ! -------
  63. ! increment time and set newday/newmonth/newyr switches
  64. !
  65. ! influences
  66. ! ----------
  67. ! nstep,itau,idate,newyr,newmonth,newday,newsrun
  68. !
  69. ! externals
  70. ! ---------
  71. ! subroutines: tau2date
  72. ! tstamp
  73. !-----------------------------------------------------------------------
  74. subroutine inctime
  75. use dims, only : ndyn,tref,idate,itau,nstep,revert,nregions
  76. use dims, only : newyr,newmonth,newday,newsrun, newhour
  77. ! local
  78. integer :: ninc, k
  79. integer,dimension(6) :: idtmp
  80. !
  81. ! add time step of ninc seconds
  82. ninc=ndyn/(2*tref(1)) !cmk !region = 1 is master
  83. !
  84. nstep=nstep+1
  85. itau=itau+revert*ninc
  86. do k=1,6
  87. idtmp(k)=idate(k)
  88. end do
  89. call tau2date(itau,idate)
  90. !
  91. ! set switches
  92. !
  93. newyr = ( idate(1) /= idtmp(1) )
  94. newmonth = ( idate(2) /= idtmp(2) )
  95. newday = ( idate(3) /= idtmp(3) )
  96. newhour(:) = ( idate(4) /= idtmp(4) )
  97. newsrun = .false.
  98. end subroutine inctime
  99. subroutine tau2date(itaux,idatex)
  100. !-----------------------------------------------------------------------
  101. !**** tau2date
  102. !
  103. ! purpose
  104. ! -------
  105. ! calculate date from given time in seconds
  106. !
  107. ! parameters
  108. ! ----------
  109. ! on input : itaux contains date/time in seconds
  110. ! on output: idatex contains date in year,month,day,hour,min,sec
  111. !
  112. ! dependencies
  113. ! ------------
  114. ! icalendo determines the type calendar used for the conversion
  115. ! iyear0 is the reference year for the calculation
  116. ! julday0 is the reference julian day for the calculation
  117. !
  118. ! externals
  119. ! ---------
  120. ! subroutines: caldat
  121. ! funtions: julday
  122. !-----------------------------------------------------------------------
  123. use dims, only : icalendo, iyear0, julday0
  124. implicit none
  125. ! input/output
  126. integer(kind=8), intent(in) :: itaux
  127. integer,dimension(6),intent(out) :: idatex
  128. ! local
  129. integer :: julian
  130. integer :: idayy,iyeary,idummy
  131. !
  132. ! compute time (hour,min,sec) and number of days
  133. !
  134. idatex(6)=mod(itaux,60)
  135. idatex(5)=mod(itaux/60,60)
  136. idatex(4)=mod(itaux/3600,24)
  137. idayy=itaux/86400
  138. !
  139. ! permanent 360 year calendar with 30 days in each month
  140. !
  141. if ( icalendo == 1 ) then
  142. idatex(3)=mod(idayy,30)+1
  143. idatex(2)=mod(idayy/30,12)+1
  144. idatex(1)=iyear0+idayy/360
  145. !
  146. ! real calendar
  147. !
  148. else if ( icalendo == 2 ) then
  149. julian=julday0+idayy
  150. call caldat(julian,idatex(2),idatex(3),idatex(1))
  151. !
  152. ! permanent 365 day year calendar
  153. !
  154. else if ( icalendo == 3 ) then
  155. iyeary=idayy/365
  156. idatex(1)=iyear0+iyeary
  157. ! use Jan 1, 1981 as a year containing 365 days and add doy
  158. julian=julday(1,1,1981)+idayy-iyeary*365
  159. call caldat(julian,idatex(2),idatex(3),idummy)
  160. !
  161. ! permanent leap year calendar
  162. !
  163. else if ( icalendo == 4 ) then
  164. iyeary=idayy/366
  165. idatex(1)=iyear0+iyeary
  166. ! use Jan 1, 1980 as a year containing 366 days and add doy
  167. julian=julday(1,1,1980)+idayy-iyeary*366
  168. call caldat(julian,idatex(2),idatex(3),idummy)
  169. !
  170. ! illegal option icalendo
  171. !
  172. else
  173. write(*,*) ' tau2date: ERROR while computing date'
  174. write(*,*) ' tau2date: Illegal calendar type'
  175. write(*,*) ' icalendo = ',icalendo
  176. stop
  177. end if
  178. end subroutine tau2date
  179. subroutine date2tau(idatex,itaux)
  180. !-----------------------------------------------------------------------
  181. !**** date2tau
  182. !
  183. ! purpose
  184. ! -------
  185. ! calculate time in seconds from given date
  186. !
  187. ! parameters
  188. ! ----------
  189. ! on input : idatex contains date in year,month,day,hour,min,sec
  190. ! on output: itaux contains date/time in seconds
  191. !
  192. ! dependencies
  193. ! ------------
  194. ! icalendo determines the type calendar used for the conversion
  195. ! iyear0 is the reference year for the calculation
  196. ! julday0 is the reference julian day for the calculation
  197. !
  198. ! externals
  199. ! ---------
  200. ! funtions: julday
  201. !-----------------------------------------------------------------------
  202. use dims, only : icalendo, iyear0, julday0, kmain
  203. implicit none
  204. ! input/output
  205. integer,dimension(6), intent(in) :: idatex
  206. integer(kind=8), intent(out) :: itaux
  207. ! local
  208. integer :: idaysec
  209. !
  210. ! compute the seconds the day is old
  211. !
  212. idaysec=idatex(6)+idatex(5)*60+idatex(4)*3600
  213. !
  214. ! permanent 360 year calendar with 30 days in each month
  215. !
  216. if ( icalendo == 1 ) then
  217. itaux=idaysec+(idatex(3)-1)*86400+(idatex(2)-1)*2592000 &
  218. +(idatex(1)-iyear0)*31104000
  219. !
  220. ! real calendar
  221. !
  222. else if ( icalendo == 2 ) then
  223. itaux=86400*(julday(idatex(2),idatex(3),idatex(1))-julday0)+idaysec
  224. !
  225. ! permanent 365 day year calendar
  226. !
  227. else if ( icalendo == 3 ) then
  228. itaux=86400*(julday(idatex(2),idatex(3),1981)-julday(1,1,1981)) &
  229. +(idatex(1)-iyear0)*365*86400+idaysec
  230. !
  231. ! permanent leap year calendar
  232. !
  233. else if ( icalendo == 4 ) then
  234. itaux=86400*(julday(idatex(2),idatex(3),1980)-julday(1,1,1980)) &
  235. +(idatex(1)-iyear0)*366*86400+idaysec
  236. !
  237. ! illegal option icalendo
  238. !
  239. else
  240. write(kmain,*) ' date2tau: ERROR while computing time'
  241. write(kmain,*) ' date2tau: Illegal calendar type'
  242. write(kmain,*) ' icalendo = ',icalendo
  243. stop
  244. end if
  245. end subroutine date2tau
  246. integer function get_day(mm,dd,mlen)
  247. !
  248. ! returns day number (from 1 January)
  249. !
  250. implicit none
  251. ! input/output
  252. integer,intent(in) :: mm ! month in year
  253. integer,intent(in) :: dd ! day in month, year
  254. integer,intent(in),dimension(12) :: mlen !lengt of months (days)
  255. ! local
  256. integer :: m
  257. get_day = 0
  258. do m=1,mm-1
  259. get_day = get_day + mlen(m)
  260. enddo
  261. get_day = get_day + dd
  262. end function get_day
  263. integer function julday(mm,id,iy)
  264. !-----------------------------------------------------------------------
  265. !**** julday
  266. !
  267. ! purpose
  268. ! -------
  269. ! calculate julian day from given date
  270. !
  271. ! parameters
  272. ! ----------
  273. ! on input : mm, id, iyyy contain month, day and year
  274. ! on output: julday contains the julian day
  275. !
  276. ! dependencies
  277. ! ------------
  278. ! julday0 is the reference julian day for the calculation
  279. !
  280. ! reference
  281. ! ---------
  282. ! J. Meeuws, "Astronomical formulea for calculators" 19xx
  283. !-----------------------------------------------------------------------
  284. implicit none
  285. ! input, output
  286. integer,intent(in) :: mm ! month
  287. integer,intent(in) :: id ! day
  288. integer,intent(in) :: iy ! year
  289. ! local
  290. integer,parameter :: igreg=15+31*(10+12*1582)
  291. integer :: julday0, jy, jm, ja, iyyy
  292. ! handle dates before 0 AD
  293. !
  294. iyyy=iy
  295. if ( iy == 0 ) then
  296. stop 'julday: ERROR invalid year 0 AD'
  297. end if
  298. if ( iy < 0 ) then
  299. iyyy=iy+1
  300. end if
  301. !
  302. !calculate julian day from date in gregorian calendar
  303. !
  304. if ( mm > 2 ) then
  305. jy=iyyy
  306. jm=mm+1
  307. else
  308. jy=iyyy-1
  309. jm=mm+13
  310. end if
  311. julday=int(365.25*jy)+int(30.6001*jm)+id+1720995
  312. !
  313. !handle julian calender
  314. !
  315. if ( id+31*(mm+12*iyyy) >= igreg ) then
  316. ja=int(0.01*jy)
  317. julday=julday+2-ja+int(0.25*ja)
  318. end if
  319. end function julday
  320. subroutine caldat(julian,mm,id,iyyy)
  321. !-----------------------------------------------------------------------
  322. !**** caldat
  323. !
  324. ! purpose
  325. ! -------
  326. ! calculate date from given julian day
  327. !
  328. ! parameters
  329. ! ----------
  330. ! on input : julday contains the julian day
  331. ! on output: mm, id, iyyy contain month, day and year
  332. !
  333. ! dependencies
  334. ! ------------
  335. ! julday0 is the reference julian day for the calculation
  336. !
  337. ! reference
  338. ! ---------
  339. ! J. Meeuws, "Astronomical formulea for calculators" 19xx
  340. !-----------------------------------------------------------------------
  341. implicit none
  342. ! input/output
  343. integer,intent(in) :: julian
  344. integer,intent(out) :: mm
  345. integer,intent(out) :: id
  346. integer,intent(out) :: iyyy
  347. ! local
  348. integer,parameter :: igreg=2299161
  349. integer :: jalpha, ja, jb, jc, jd, je
  350. !
  351. ! handle gregorian and julian date
  352. !
  353. if ( julian >= igreg )then
  354. jalpha=int(((julian-1867216)-0.25)/36524.25)
  355. ja=julian+1+jalpha-int(0.25*jalpha)
  356. else
  357. ja=julian
  358. end if
  359. jb=ja+1524
  360. jc=int(6680.+((jb-2439870)-122.1)/365.25)
  361. jd=365*jc+int(0.25*jc)
  362. je=int((jb-jd)/30.6001)
  363. id=jb-jd-int(30.6001*je)
  364. mm=je-1
  365. if ( mm > 12 ) mm=mm-12
  366. iyyy=jc-4715
  367. if ( mm > 2 ) iyyy=iyyy-1
  368. !
  369. ! handle dates before 0 AD
  370. !
  371. if ( iyyy <= 0 ) iyyy=iyyy-1
  372. end subroutine caldat
  373. subroutine calc_sm( mlen, sec_day, sec_month, sec_year )
  374. !
  375. !
  376. !
  377. use dims, only : icalendo, idate
  378. implicit none
  379. ! input/output
  380. real,intent(out) :: sec_day ! # seconds in day
  381. real,intent(out) :: sec_month ! # seconds in current month
  382. real,intent(out) :: sec_year ! # seconds in current year
  383. integer,intent(out),dimension(12):: mlen ! days per month (current year)
  384. ! start
  385. sec_day=86400.
  386. mlen(1)=31
  387. mlen(2)=28
  388. mlen(3)=31
  389. mlen(4)=30
  390. mlen(5)=31
  391. mlen(6)=30
  392. mlen(7)=31
  393. mlen(8)=31
  394. mlen(9)=30
  395. mlen(10)=31
  396. mlen(11)=30
  397. mlen(12)=31 ! only for regular year
  398. !
  399. ! calender option
  400. !
  401. sec_year=365.*sec_day
  402. if ( icalendo == 1 ) then
  403. mlen(:)=30
  404. sec_year=360.*sec_day
  405. end if
  406. if ( icalendo == 4 ) then
  407. mlen(2)=29
  408. sec_year=366.*sec_day
  409. end if
  410. if ( icalendo == 2 .and. (mod(idate(1),4) == 0) .and. &
  411. (mod(idate(1),100) /= 0) .or. (mod(idate(1),400) == 0) ) then
  412. mlen(2)=29
  413. sec_year=366.*sec_day
  414. end if
  415. sec_month=sec_day*mlen(idate(2))
  416. !write(*,*) 'calc_sm: sec_month',sec_month
  417. end subroutine calc_sm
  418. subroutine dayl(day,daylen,jdim,lat_start,dlat)
  419. !
  420. !*** calculates daylength (hours) depending on
  421. !*** latitude (phi) and day of year (day)
  422. !
  423. ! programmed by:
  424. ! implemented by: fd IMAU Tue Feb 27 17:51:57 MET 1997
  425. ! modified by MK for zoom version may 2001
  426. ! purpose
  427. ! -------
  428. ! calculates daylength
  429. !
  430. ! interface
  431. ! ---------
  432. ! call dayl(day,daylen,jdim,lat_start,dlat)
  433. !
  434. ! day : the day of the year based on 365 days a year
  435. ! daylen(jdim) : length of day at jdim latitudes
  436. ! lat_start : first latitude (degrees from -90 to +90)
  437. ! at the southernmost edge
  438. ! dlat : increment
  439. !
  440. ! method
  441. ! ------
  442. ! none
  443. !
  444. ! external
  445. ! ---------
  446. ! none
  447. !
  448. ! reference
  449. ! ---------
  450. !
  451. !-------------------------------
  452. implicit none
  453. ! input/output
  454. integer,intent(in) :: day ! the day of the year
  455. integer,intent(in) :: jdim ! dimension of daylen
  456. real,intent(out),dimension(jdim) :: daylen ! length of day at jdim lats
  457. real,intent(in) :: lat_start ! first latitude
  458. real,intent(in) :: dlat ! latitude increment
  459. ! local
  460. real :: nj,dj,phi,td,a,phix,xh,pi
  461. integer :: j,idayy=365
  462. ! start
  463. pi = acos(-1.0)
  464. dj= dlat
  465. do j=1,jdim
  466. phix = (lat_start+(j-0.5)*dj)*pi/180.
  467. td = -float(mod(day+10,idayy))*2.*pi/idayy
  468. a = cos(td)*pi/180.*23.45
  469. xh = tan(a)*tan(phix)
  470. if ( abs(xh) <= 1. ) then
  471. ! CMK BUG: N-S reversal removed dec2004
  472. daylen(j) = 24*(1-acos(-xh)/pi)
  473. else
  474. if ( xh <= -1 ) daylen(j) = 24.0
  475. if ( xh >= 1 ) daylen(j) = 0.0
  476. end if
  477. end do ! j
  478. end subroutine dayl
  479. !----------------------------------------------------------------------
  480. ! write time stamp and msg on unit kunit
  481. !----------------------------------------------------------------------
  482. subroutine tstamp( kunit, itaux, msg )
  483. use GO, only : gol, goPr
  484. ! --- in/out -----------------------
  485. integer, intent(in) :: kunit ! unit to write "tstamp" to <--- ignored
  486. integer(kind=8), intent(in) :: itaux ! "tstamp" time
  487. character(len=*), intent(in) :: msg ! "tstamp" message
  488. ! --- begin ---------------------
  489. call wrtgol_tstamp( itaux, msg ); call goPr
  490. end subroutine tstamp
  491. ! ***
  492. subroutine wrtgol_tstamp( itaux, msg )
  493. use GO, only : gol, goPr
  494. ! --- in/out -----------------------
  495. integer(kind=8), intent(in) :: itaux ! "tstamp" time
  496. character(len=*), intent(in) :: msg ! "tstamp" message
  497. ! --- local ----------------------
  498. integer,dimension(6) :: idatex
  499. character(len=24) :: cdate
  500. ! --- begin ---------------------
  501. ! convert from seconds to year/month/etc:
  502. call tau2date(itaux,idatex)
  503. ! write in characters:
  504. call chardate(idatex,cdate)
  505. ! depricated ...
  506. !write (kunit,'(a1,a24,a1,a)') ' ',cdate,' ',msg
  507. ! display:
  508. write (gol,'(a24," ",a)') cdate, trim(msg)
  509. end subroutine wrtgol_tstamp
  510. ! ***
  511. subroutine new_valid_timestep( dtime, nread, cfl_outputstep)
  512. use dims, only : nregions, tref
  513. ! --- in/out -------------------------
  514. integer, intent(inout) :: dtime ! current timestep
  515. ! to be replaced with a valid new timestep
  516. integer, intent(in) :: nread ! nread (e.g. 3hr) should be a
  517. ! multiple of the new 'valid' timestep
  518. integer, intent(in) :: cfl_outputstep ! choose times
  519. ! --- begin -----------------------------
  520. ! loop until time is largest multiple of nread, clf_outputstep, and 2*tref
  521. do
  522. dtime = dtime-1
  523. if (mod(nread,dtime) == 0 .and. mod(cfl_outputstep,dtime) == 0 .and.&
  524. mod(dtime,maxval(2*tref(1:nregions))) == 0) exit
  525. if (dtime < maxval(2*tref(1:nregions))) then
  526. write (gol,'("no valid timestep found:")'); call goPr
  527. write (gol,'(" dtime (s) : ",i8)') dtime; call goErr
  528. write (gol,'(" nread (s) : ",i8)') nread; call goErr
  529. write (gol,'(" cfl_outputstep (s) : ",i8)') cfl_outputstep; call goErr
  530. write (gol,'("STOP in ",a)') 'datetime/new_valid_timestep'; call goErr; stop
  531. end if
  532. enddo
  533. end subroutine new_valid_timestep
  534. real*8 function idate2ddate ( idate )
  535. ! computes the decimal date given a calendar date
  536. ! 21 Oct 2011, M. Trudeau
  537. implicit none
  538. integer, dimension(6), intent(in) :: idate
  539. integer :: siy
  540. integer(kind=8) :: itau, itau_ref, itau_bgn, itau_end
  541. logical :: is_leap
  542. call date2tau((/idate(1), 1, 1, 0, 0, 0/), itau_ref)
  543. call date2tau(idate, itau)
  544. is_leap = (mod(idate(1), 4) == 0 .and. .not. mod(idate(1), 100) == 0) .or. (mod(idate(1), 400) == 0)
  545. if ( is_leap ) then
  546. siy = 31622400
  547. else
  548. siy = 31536000
  549. endif
  550. idate2ddate = dble(idate(1)) + dble(itau - itau_ref) / dble(siy)
  551. end function idate2ddate
  552. end module datetime