SCALE-RM
scale_calendar.F90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
14 !-------------------------------------------------------------------------------
16  !-----------------------------------------------------------------------------
17  !
18  !++ used modules
19  !
20  use scale_precision
21  use scale_stdio
22  !-----------------------------------------------------------------------------
23  implicit none
24  private
25  !-----------------------------------------------------------------------------
26  !
27  !++ Public procedure
28  !
29  public :: calendar_setup
30  public :: calendar_getdayofyear
31  public :: calendar_date2daysec
32  public :: calendar_daysec2date
33  public :: calendar_ymd2absday
34  public :: calendar_hms2abssec
35  public :: calendar_adjust_daysec
36  public :: calendar_combine_daysec
37  public :: calendar_unit2sec
38  public :: calendar_cfunits2sec
39  public :: calendar_date2char
40 
41  !-----------------------------------------------------------------------------
42  !
43  !++ Public parameters & variables
44  !
45  integer, public, parameter :: i_year = 1
46  integer, public, parameter :: i_month = 2
47  integer, public, parameter :: i_day = 3
48  integer, public, parameter :: i_hour = 4
49  integer, public, parameter :: i_min = 5
50  integer, public, parameter :: i_sec = 6
51 
52  !-----------------------------------------------------------------------------
53  !
54  !++ Private procedure
55  !
56  private :: calendar_absday2ymd
57  private :: calendar_abssec2hms
58  private :: calendar_ymdhms2nd
59  private :: calendar_ymdhms2mjd
60  private :: checkleap
61 
62  !-----------------------------------------------------------------------------
63  !
64  !++ Private parameters & variables
65  !
66  real(DP), private :: calendar_doi = 365.0_dp
67  real(DP), private :: calendar_hour = 24.0_dp
68  real(DP), private :: calendar_min = 60.0_dp
69  real(DP), private :: calendar_sec = 60.0_dp
70 
71  integer, private, parameter :: i_nonleapyear = 1
72  integer, private, parameter :: i_leapyear = 2
73  integer, private :: dayofmonth(12,2)
74  data dayofmonth / 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, & ! non-leap year
75  31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 / ! leap year
76 
77  !-----------------------------------------------------------------------------
78 contains
79  !-----------------------------------------------------------------------------
81  subroutine calendar_setup
82  implicit none
83  !---------------------------------------------------------------------------
84 
85  if( io_l ) write(io_fid_log,*)
86  if( io_l ) write(io_fid_log,*) '++++++ Module[CALENDAR] / Categ[COMMON] / Origin[SCALElib]'
87  if( io_l ) write(io_fid_log,*) '*** No namelists.'
88 
89  return
90  end subroutine calendar_setup
91 
92  !-----------------------------------------------------------------------------
94  subroutine calendar_getdayofyear( &
95  DayOfYear, &
96  iyear )
97  implicit none
98 
99  real(DP), intent(out) :: DayOfYear ! # of day of year
100  integer, intent(in) :: iyear ! current year
101  !---------------------------------------------------------------------------
102 
103  dayofyear = calendar_doi
104  if( checkleap(iyear) ) dayofyear = calendar_doi + 1.0_dp
105 
106  return
107  end subroutine calendar_getdayofyear
108 
109  !-----------------------------------------------------------------------------
111  subroutine calendar_date2daysec( &
112  absday, &
113  abssec, &
114  ymdhms, &
115  subsec, &
116  offset_year )
117  implicit none
118 
119  integer, intent(out) :: absday
120  real(DP), intent(out) :: abssec
121  integer, intent(in) :: ymdhms(6)
122  real(DP), intent(in) :: subsec
123  integer, intent(in) :: offset_year
124  !---------------------------------------------------------------------------
125 
126  call calendar_ymd2absday( absday, & ! [OUT]
127  ymdhms(i_year), & ! [IN]
128  ymdhms(i_month), & ! [IN]
129  ymdhms(i_day), & ! [IN]
130  offset_year ) ! [IN]
131 
132  call calendar_hms2abssec( abssec, & ! [OUT]
133  ymdhms(i_hour), & ! [IN]
134  ymdhms(i_min), & ! [IN]
135  ymdhms(i_sec), & ! [IN]
136  subsec ) ! [IN]
137 
138  return
139  end subroutine calendar_date2daysec
140 
141  !-----------------------------------------------------------------------------
143  subroutine calendar_daysec2date( &
144  ymdhms, &
145  subsec, &
146  absday, &
147  abssec, &
148  offset_year )
149  implicit none
150 
151  integer, intent(out) :: ymdhms(6)
152  real(DP), intent(out) :: subsec
153  integer, intent(in) :: absday
154  real(DP), intent(in) :: abssec
155  integer, intent(in) :: offset_year
156  !---------------------------------------------------------------------------
157 
158  call calendar_absday2ymd( ymdhms(i_year), & ! [OUT]
159  ymdhms(i_month), & ! [OUT]
160  ymdhms(i_day), & ! [OUT]
161  absday, & ! [IN]
162  offset_year ) ! [IN]
163 
164  call calendar_abssec2hms( ymdhms(i_hour), & ! [OUT]
165  ymdhms(i_min), & ! [OUT]
166  ymdhms(i_sec), & ! [OUT]
167  subsec, & ! [OUT]
168  abssec ) ! [IN]
169 
170  return
171  end subroutine calendar_daysec2date
172 
173  !-----------------------------------------------------------------------------
175  subroutine calendar_ymd2absday( &
176  absday, &
177  gyear, &
178  gmonth, &
179  gday, &
180  oyear )
181  implicit none
182 
183  integer, intent(out) :: absday
184  integer, intent(in) :: gyear
185  integer, intent(in) :: gmonth
186  integer, intent(in) :: gday
187  integer, intent(in) :: oyear
188 
189  integer :: gyear_mod, gmonth_mod
190  integer :: yearday, monthday
191  integer :: m, ileap
192  !---------------------------------------------------------------------------
193 
194  gmonth_mod = mod( gmonth-1, 12 ) + 1
195  gyear_mod = gyear + ( gmonth-gmonth_mod ) / 12
196 
197  yearday = int( calendar_doi * ( gyear_mod - oyear ) ) &
198  + int( real(gyear_mod-1,kind=DP) / 4.0_DP ) &
199  - int( real(gyear_mod-1,kind=DP) / 100.0_dp ) &
200  + int( real(gyear_mod-1,kind=DP) / 400.0_dp ) &
201  - int( real(oyear -1,kind=DP) / 4.0_dp ) &
202  + int( real(oyear -1,kind=DP) / 100.0_dp ) &
203  - int( real(oyear -1,kind=DP) / 400.0_dp )
204 
205  ileap = i_nonleapyear
206  if( checkleap(gyear_mod) ) ileap = i_leapyear
207 
208  monthday = 0
209  do m = 1, gmonth_mod-1
210  monthday = monthday + dayofmonth(m,ileap)
211  enddo
212 
213  absday = yearday + monthday + gday - 1
214 
215  return
216  end subroutine calendar_ymd2absday
217 
218  !-----------------------------------------------------------------------------
220  subroutine calendar_absday2ymd( &
221  gyear, &
222  gmonth, &
223  gday, &
224  absday, &
225  oyear )
226  implicit none
227 
228  integer, intent(out) :: gyear
229  integer, intent(out) :: gmonth
230  integer, intent(out) :: gday
231  integer, intent(in) :: absday
232  integer, intent(in) :: oyear
233 
234  integer :: checkday
235  integer :: i, ileap
236  !---------------------------------------------------------------------------
237 
238  gyear = int( real(absday,kind=DP) / 366.0_DP ) + oyear ! first guess
239  do i = 1, 1000
240  call calendar_ymd2absday( checkday, gyear+1, 1, 1, oyear )
241  if( absday < checkday ) exit
242  gyear = gyear + 1
243  enddo
244 
245  ileap = i_nonleapyear
246  if( checkleap(gyear) ) ileap = i_leapyear
247 
248  gmonth = 1
249  do i = 1, 1000
250  call calendar_ymd2absday( checkday, gyear, gmonth, dayofmonth(gmonth,ileap), oyear )
251  if( absday <= checkday ) exit
252  gmonth = gmonth + 1
253  enddo
254 
255  call calendar_ymd2absday( checkday, gyear, gmonth, 1, oyear )
256  gday = absday - checkday + 1
257 
258  return
259  end subroutine calendar_absday2ymd
260 
261  !-----------------------------------------------------------------------------
263  subroutine calendar_hms2abssec( &
264  abssec, &
265  hour, &
266  minute, &
267  second, &
268  subsec )
269  implicit none
270 
271  real(DP), intent(out) :: abssec
272  integer, intent(in) :: hour
273  integer, intent(in) :: minute
274  integer, intent(in) :: second
275  real(DP), intent(in) :: subsec
276  !---------------------------------------------------------------------------
277 
278  abssec = real(hour, kind=DP) * CALENDAR_MIN * CALENDAR_SEC &
279  + real(minute,kind=DP) * CALENDAR_SEC &
280  + real(second,kind=DP) &
281  + subsec
282 
283  return
284  end subroutine calendar_hms2abssec
285 
286  !-----------------------------------------------------------------------------
288  subroutine calendar_abssec2hms( &
289  hour, &
290  minute, &
291  second, &
292  subsec, &
293  abssec )
294  implicit none
295 
296  integer, intent(out) :: hour
297  integer, intent(out) :: minute
298  integer, intent(out) :: second
299  real(DP), intent(out) :: subsec
300  real(DP), intent(in) :: abssec
301 
302  real(DP) :: nsec, nmin, nhour, temp
303  !---------------------------------------------------------------------------
304 
305  nsec = real(int(abssec),kind=dp)
306  subsec = abssec - nsec
307 
308  temp = mod( nsec, calendar_sec )
309  second = int( temp )
310  nmin = ( nsec-temp ) / calendar_sec
311 
312  temp = mod( nmin, calendar_min )
313  minute = int( temp )
314  nhour = ( nmin-temp ) / calendar_min
315 
316  temp = mod( nhour, calendar_hour )
317  hour = int( temp )
318 
319  return
320  end subroutine calendar_abssec2hms
321 
322  !-----------------------------------------------------------------------------
324  subroutine calendar_adjust_daysec( &
325  absday, &
326  abssec )
327  implicit none
328 
329  integer, intent(inout) :: absday
330  real(DP), intent(inout) :: abssec
331 
332  integer :: addday
333  !---------------------------------------------------------------------------
334 
335  addday = int( abssec / ( calendar_hour * calendar_min * calendar_sec ) )
336 
337  absday = absday + addday
338 
339  abssec = abssec - real(addday,kind=DP) * CALENDAR_HOUR * CALENDAR_MIN * CALENDAR_SEC
340 
341  return
342  end subroutine calendar_adjust_daysec
343 
344  !-----------------------------------------------------------------------------
346  function calendar_combine_daysec( absday, abssec ) result(daysec)
347  implicit none
348 
349  integer, intent(in) :: absday
350  real(DP), intent(in) :: abssec
351  real(DP) :: daysec
352  !---------------------------------------------------------------------------
353 
354  daysec = real(absday,kind=DP) * CALENDAR_SEC * CALENDAR_MIN * CALENDAR_HOUR &
355  + abssec
356 
357  return
358  end function calendar_combine_daysec
359 
360  !-----------------------------------------------------------------------------
362  subroutine calendar_unit2sec( &
363  second, &
364  value, &
365  unit )
366  use scale_process, only: &
368  implicit none
369 
370  real(DP), intent(out) :: second
371  real(DP), intent(in) :: value
372  character(len=*), intent(in) :: unit
373  !---------------------------------------------------------------------------
374 
375  select case(unit)
376  case('MSEC')
377  second = value * 1.e-3_dp
378  case('SEC', 'seconds')
379  second = value
380  case('MIN')
381  second = value * calendar_sec
382  case('HOUR')
383  second = value * calendar_sec * calendar_min
384  case('DAY')
385  second = value * calendar_sec * calendar_min * calendar_hour
386  case default
387  write(*,*) ' xxx Unsupported UNIT: ', trim(unit), ', ', value
388  call prc_mpistop
389  endselect
390 
391  return
392  end subroutine calendar_unit2sec
393 
394  !-----------------------------------------------------------------------------
396  function calendar_cfunits2sec( cftime, cfunits, offset_year, startdaysec ) result( sec )
397  use scale_process, only: &
399  implicit none
400  real(DP), intent(in) :: cftime
401  character(len=*), intent(in) :: cfunits
402  integer, intent(in) :: offset_year
403  real(DP), intent(in), optional :: startdaysec
404  real(DP) :: sec
405 
406  character(len=H_MID) :: tunit
407  character(len=H_MID) :: buf
408 
409  integer :: date(6)
410  integer :: day
411  real(DP) :: sec0
412 
413  integer :: l
414 
415  intrinsic index
416 
417  l = index(cfunits, " since ")
418  if ( l > 1 ) then ! untis is under the CF convension
419  tunit = cfunits(1:l-1)
420  buf = cfunits(l+7:)
421 
422  l = index(buf, "-")
423  if ( l /= 5 ) then
424  write(*,*) 'xxx units for time is invalid (year): ', trim(cfunits), ' ', trim(buf)
425  call prc_mpistop
426  end if
427  read( buf(1:4), *) date(1) ! year
428  buf = buf(6:)
429 
430  l = index(buf, "-")
431  if ( l /= 3 ) then
432  write(*,*) 'xxx units for time is invalid (month): ', trim(cfunits), ' ', trim(buf)
433  call prc_mpistop
434  end if
435  read( buf(1:2), *) date(2) ! month
436  buf = buf(4:)
437 
438  l = index(buf, " ")
439  if ( l /= 3 ) then
440  write(*,*) 'xxx units for time is invalid (day): ', trim(cfunits), ' ', trim(buf)
441  call prc_mpistop
442  end if
443  read( buf(1:2), *) date(3) ! day
444  buf = buf(4:)
445 
446  l = index(buf, ":")
447  if ( l /= 3 ) then
448  write(*,*) 'xxx units for time is invalid (hour): ', trim(cfunits), ' ', trim(buf)
449  call prc_mpistop
450  end if
451  read( buf(1:2), *) date(4) ! hour
452  buf = buf(4:)
453 
454  l = index(buf, ":")
455  if ( l /= 3 ) then
456  write(*,*) 'xxx units for time is invalid (min): ', trim(cfunits), ' ', trim(buf)
457  call prc_mpistop
458  end if
459  read( buf(1:2), *) date(5) ! min
460  buf = buf(4:)
461 
462  if ( len_trim(buf) /= 2 ) then
463  write(*,*) 'xxx units for time is invalid (sec): ', trim(cfunits), ' ', trim(buf), len_trim(buf)
464  call prc_mpistop
465  end if
466  read( buf(1:2), *) date(6) ! sec
467 
468  call calendar_date2daysec( day, & ! (out)
469  sec0, & ! (out)
470  date(:), & ! (in)
471  0.0_dp, & ! (in)
472  offset_year ) ! (in)
473 
474  sec0 = calendar_combine_daysec( day, sec0 )
475  else
476  tunit = cfunits
477  if ( present(startdaysec) ) then
478  sec0 = startdaysec
479  else
480  sec0 = 0.0_dp
481  end if
482  end if
483 
484  call calendar_unit2sec(sec, cftime, tunit)
485 
486  sec = sec0 + sec
487 
488  return
489  end function calendar_cfunits2sec
490 
491  !-----------------------------------------------------------------------------
493  subroutine calendar_date2char( &
494  chardate, &
495  ymdhms, &
496  subsec )
497  implicit none
498 
499  character(len=27), intent(out) :: chardate
500  integer, intent(in) :: ymdhms(6)
501  real(DP), intent(in) :: subsec
502  !---------------------------------------------------------------------------
503 
504  write(chardate,'(I4.4,A1,I2.2,A1,I2.2,A1,I2.2,A1,I2.2,A1,I2.2,A2,F6.3)') &
505  ymdhms(1),'/',ymdhms(2),'/',ymdhms(3),' ', &
506  ymdhms(4),':',ymdhms(5),':',ymdhms(6),' +', &
507  subsec
508 
509  return
510  end subroutine calendar_date2char
511 
512  !-----------------------------------------------------------------------------
515  function checkleap( iyear )
516  implicit none
517 
518  integer, intent(in) :: iyear
519  logical :: checkleap
520 
521  integer :: check4, check100, check400
522  !---------------------------------------------------------------------------
523 
524  check4 = mod(iyear,4 )
525  check100 = mod(iyear,100)
526  check400 = mod(iyear,400)
527 
528  checkleap = .false.
529  if( check4 == 0 ) checkleap = .true.
530  if( check100 == 0 ) checkleap = .false.
531  if( check400 == 0 ) checkleap = .true.
532 
533  end function checkleap
534 
535  !-----------------------------------------------------------------------------
537  subroutine calendar_ymdhms2nd( &
538  nd, &
539  ymdhms, &
540  oyear )
541  implicit none
542 
543  real(DP), intent(out) :: nd
544  integer, intent(in) :: ymdhms(6)
545  integer, intent(in) :: oyear
546 
547  integer :: absday, absday_jan1
548  !---------------------------------------------------------------------------
549 
550  call calendar_ymd2absday( absday, & ! [OUT]
551  ymdhms(i_year), & ! [IN]
552  ymdhms(i_month), & ! [IN]
553  ymdhms(i_day), & ! [IN]
554  oyear ) ! [IN]
555 
556  call calendar_ymd2absday( absday_jan1, & ! [OUT]
557  ymdhms(i_year), & ! [IN]
558  1, & ! [IN]
559  1, & ! [IN]
560  oyear ) ! [IN]
561 
562  nd = absday - absday_jan1 + 1.0_dp
563 
564  return
565  end subroutine calendar_ymdhms2nd
566 
567  !-----------------------------------------------------------------------------
569  subroutine calendar_ymdhms2mjd( &
570  mjd, &
571  ymdhms, &
572  oyear )
573  implicit none
574 
575  real(DP), intent(out) :: mjd
576  integer, intent(in) :: ymdhms(6)
577  integer, intent(in) :: oyear
578 
579  integer :: y, m, mjd_day
580  !---------------------------------------------------------------------------
581 
582  if ( ymdhms(i_month) == 1 &
583  .OR. ymdhms(i_month) == 2 ) then
584  y = ymdhms(i_year) - 1
585  m = ymdhms(i_month) + 2
586  else
587  y = ymdhms(i_year)
588  m = ymdhms(i_month)
589  endif
590 
591  mjd_day = int( 365.25_dp * y ) & ! year
592  + int( y/400.0_dp ) - int( y/100.0_dp ) & ! leap year
593  + int( 30.59_dp * m-2 ) & ! month
594  + ymdhms(i_day) & ! day
595  + 678912 ! constant
596 
597  mjd = real(mjd_day,kind=DP) & ! day
598  + ymdhms(i_hour) / 24.0_DP & ! hour
599  + ymdhms(i_min) / 1440.0_DP & ! min
600  + ymdhms(i_sec) / 86400.0_DP ! sec
601 
602  return
603  end subroutine calendar_ymdhms2mjd
604 
605 end module scale_calendar
606 !-------------------------------------------------------------------------------
integer, parameter, public i_month
[index] month
subroutine, public calendar_unit2sec(second, value, unit)
Convert several units to second.
integer, parameter, public i_year
[index] year
subroutine, public prc_mpistop
Abort MPI.
real(dp) function, public calendar_combine_daysec(absday, abssec)
Combine day and second.
subroutine, public calendar_ymd2absday(absday, gyear, gmonth, gday, oyear)
Convert from gregorian date to absolute day, DAY 0 is AD1/1/1.
subroutine, public calendar_date2char(chardate, ymdhms, subsec)
Convert from gregorian date to absolute day/second.
logical, public io_l
output log or not? (this process)
Definition: scale_stdio.F90:59
module STDIO
Definition: scale_stdio.F90:12
subroutine, public calendar_adjust_daysec(absday, abssec)
Adjust day and second.
subroutine, public calendar_setup
Setup.
real(dp) function, public calendar_cfunits2sec(cftime, cfunits, offset_year, startdaysec)
Convert time in units of the CF convention to second.
integer, parameter, public i_min
[index] minute
integer, parameter, public dp
Definition: dc_types.f90:27
module PROCESS
integer, parameter, public i_sec
[index] second
integer, parameter, public i_hour
[index] hour
integer, parameter, public i_day
[index] day
subroutine, public calendar_daysec2date(ymdhms, subsec, absday, abssec, offset_year)
Convert from gregorian date to absolute day/second.
module PRECISION
module CALENDAR
subroutine, public calendar_getdayofyear(DayOfYear, iyear)
Get day of year.
subroutine, public calendar_hms2abssec(abssec, hour, minute, second, subsec)
Hour, minute, second, subsecond -> absolute second.
integer, public io_fid_log
Log file ID.
Definition: scale_stdio.F90:56
subroutine, public calendar_date2daysec(absday, abssec, ymdhms, subsec, offset_year)
Convert from gregorian date to absolute day/second.