45 integer,
public,
parameter ::
i_year = 1
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
61 private :: calendar_absday2ymd
62 private :: calendar_abssec2hms
63 private :: calendar_ymdhms2nd
64 private :: calendar_ymdhms2mjd
71 logical,
private :: calendar_360days = .false.
72 logical,
private :: calendar_365days = .false.
73 logical,
private :: calendar_user = .false.
75 integer,
private,
parameter :: i_nonleapyear = 1
76 integer,
private,
parameter :: i_leapyear = 2
77 integer,
private,
parameter :: i_360days = 3
78 integer,
private,
parameter :: i_user = 4
80 integer,
private :: dayofmonth(12,4)
81 data dayofmonth / 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, &
82 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, &
83 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, &
84 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /
86 integer,
private :: calendar_user_defined(12)
87 integer,
private :: calendar_month = 12
88 logical,
private :: debug = .false.
99 namelist / param_calendar / &
105 calendar_user_defined, &
112 log_info(
"CALENDAR_setup",*)
'Setup'
114 calendar_user_defined(:) = 0
120 log_info(
"CALENDAR_setup",*)
'Not found namelist. Default used.'
121 elseif( ierr > 0 )
then
122 log_error(
"CALENDAR_setup",*)
'Not appropriate names in namelist PARAM_CALENDAR. Check!'
125 log_nml(param_calendar)
128 log_info(
"CALENDAR_setup",*)
'Calendar settings'
129 if ( maxval(calendar_user_defined) > 0 )
then
130 dayofmonth(:,i_user) = calendar_user_defined(:)
132 calendar_user = .true.
133 log_info_cont(*)
'DayOfYear = ', int(
calendar_doi),
' : user defined calendar'
135 if ( calendar_user_defined(i) > 0 )
then
136 log_info_cont(*)
'month #', i,
': ', calendar_user_defined(i),
"days"
138 calendar_month = i - 1
142 elseif( calendar_360days )
then
144 log_info_cont(*)
'DayOfYear = 360 : ideal setting'
145 elseif( calendar_365days )
then
147 log_info_cont(*)
'DayOfYear = 365 : ideal setting'
149 log_info_cont(*)
'DayOfYear = 365 or 366 : Gregorian calendar'
153 log_error(
"CALENDAR_setup",*)
'CALENDAR_SEC must be a natural number!'
156 log_error(
"CALENDAR_setup",*)
'CALENDAR_MIN must be a natural number!'
159 log_error(
"CALENDAR_setup",*)
'CALENDAR_HOUR must be a natural number!'
174 real(
dp),
intent(out) :: dayofyear
175 integer,
intent(in) :: iyear
179 if( checkleap(iyear) ) dayofyear =
calendar_doi + 1.0_dp
194 integer,
intent(out) :: absday
195 real(
dp),
intent(out) :: abssec
196 integer,
intent(in) :: ymdhms(6)
197 real(
dp),
intent(in) :: subsec
198 integer,
intent(in) :: offset_year
200 logical :: date_error = .false.
204 if ( ymdhms(
i_month) < 1 .or. calendar_month < ymdhms(
i_month) )
then
205 log_error(
"CALENDAR_date2daysec",*)
'Inputted month does not match to the calendar.'
209 ileap = i_nonleapyear
210 if( checkleap(ymdhms(
i_year)+offset_year) ) ileap = i_leapyear
211 if( calendar_360days ) ileap = i_360days
212 if( calendar_user ) ileap = i_user
214 if ( ymdhms(
i_day ) < 1 .or. dayofmonth(ymdhms(
i_month),ileap) < ymdhms(
i_day) )
then
215 log_error(
"CALENDAR_date2daysec",*)
'Inputted day does not match to the calendar.'
219 log_error(
"CALENDAR_date2daysec",*)
'Inputted hour does not match to the calendar.'
223 log_error(
"CALENDAR_date2daysec",*)
'Inputted minute does not match to the calendar.'
227 log_error(
"CALENDAR_date2daysec",*)
'Inputted second does not match to the calendar.'
230 if( date_error )
call abort
257 integer,
intent(out) :: ymdhms(6)
258 real(
dp),
intent(out) :: subsec
259 integer,
intent(in) :: absday
260 real(
dp),
intent(in) :: abssec
261 integer,
intent(in) :: offset_year
264 call calendar_absday2ymd( ymdhms(
i_year), &
270 call calendar_abssec2hms( ymdhms(
i_hour), &
289 integer,
intent(out) :: absday
290 integer,
intent(in) :: gyear
291 integer,
intent(in) :: gmonth
292 integer,
intent(in) :: gday
293 integer,
intent(in) :: oyear
295 integer :: gyear_mod, gmonth_mod
296 integer :: yearday, monthday
300 gmonth_mod = mod( gmonth-1, calendar_month ) + 1
301 gyear_mod = gyear + ( gmonth-gmonth_mod ) / calendar_month
303 if ( calendar_360days .OR. calendar_365days .or. calendar_user)
then
307 + int( real(gyear_mod-1,kind=
dp) / 4.0_dp ) &
308 - int( real(gyear_mod-1,kind=
dp) / 100.0_dp ) &
309 + int( real(gyear_mod-1,kind=
dp) / 400.0_dp ) &
310 - int( real(oyear -1,kind=
dp) / 4.0_dp ) &
311 + int( real(oyear -1,kind=
dp) / 100.0_dp ) &
312 - int( real(oyear -1,kind=
dp) / 400.0_dp )
315 ileap = i_nonleapyear
316 if( checkleap(gyear_mod) ) ileap = i_leapyear
317 if( calendar_360days ) ileap = i_360days
318 if( calendar_user ) ileap = i_user
321 do m = 1, gmonth_mod-1
322 monthday = monthday + dayofmonth(m,ileap)
325 absday = yearday + monthday + gday - 1
332 subroutine calendar_absday2ymd( &
340 integer,
intent(out) :: gyear
341 integer,
intent(out) :: gmonth
342 integer,
intent(out) :: gday
343 integer,
intent(in) :: absday
344 integer,
intent(in) :: oyear
350 gyear = int( real(absday,kind=
dp) / (
calendar_doi+1.0_dp) ) + oyear
354 if( absday < checkday )
exit
358 ileap = i_nonleapyear
359 if( checkleap(gyear) ) ileap = i_leapyear
360 if( calendar_360days ) ileap = i_360days
361 if( calendar_user ) ileap = i_user
366 if( absday <= checkday )
exit
371 gday = absday - checkday + 1
374 end subroutine calendar_absday2ymd
386 real(
dp),
intent(out) :: abssec
387 integer,
intent(in) :: hour
388 integer,
intent(in) :: minute
389 integer,
intent(in) :: second
390 real(
dp),
intent(in) :: subsec
395 + real(second,kind=
dp) &
403 subroutine calendar_abssec2hms( &
411 integer,
intent(out) :: hour
412 integer,
intent(out) :: minute
413 integer,
intent(out) :: second
414 real(
dp),
intent(out) :: subsec
415 real(
dp),
intent(in) :: abssec
417 real(
dp) :: nsec, nmin, nhour, temp
420 nsec = real(int(abssec),kind=
dp)
421 subsec = abssec - nsec
435 end subroutine calendar_abssec2hms
444 integer,
intent(inout) :: absday
445 real(
dp),
intent(inout) :: abssec
452 absday = absday + addday
456 if ( abssec < 0.0_dp )
then
469 integer,
intent(in) :: absday
470 real(
dp),
intent(in) :: abssec
490 real(
dp),
intent(out) :: second
491 real(
dp),
intent(in) ::
value
492 character(len=*),
intent(in) :: unit
497 second =
value * 1.e-3_dp
498 case(
'SEC',
'seconds')
507 log_error(
"CALENDAR_unit2sec",*)
'Unsupported UNIT: ', trim(unit),
', ',
value
524 real(
dp),
intent(out) :: value
525 real(
dp),
intent( in) :: second
526 character(len=*),
intent( in) :: unit
529 select case(trim(unit))
531 value = second / 1.0e-3_dp
532 case(
'SEC',
'seconds',
'sec',
's')
534 case(
'MIN',
'mins',
'min')
536 case(
'HOUR',
'hours',
'hour',
'h')
538 case(
'DAY',
'days',
'day')
541 log_error(
"CALENDAR_sec2unit",*)
'Unsupported UNIT: ', trim(unit),
', ',
value
554 real(
dp),
intent(in) :: cftime
555 character(len=*),
intent(in) :: cfunits
556 integer,
intent(in) :: offset_year
557 real(
dp),
intent(in),
optional :: startdaysec
560 character(len=H_MID) :: tunit
561 character(len=H_MID) :: buf
572 l = index( cfunits,
" since " )
574 tunit = cfunits(1:l-1)
579 log_error(
"CALENDAR_CFunits2sec",*)
'units for time is invalid (year)'
580 log_error_cont(*) trim(cfunits)
581 log_error_cont(*) trim(buf)
584 read(buf(1:4),*) date(1)
589 log_error(
"CALENDAR_CFunits2sec",*)
'units for time is invalid (month)'
590 log_error_cont(*) trim(cfunits)
591 log_error_cont(*) trim(buf)
594 read(buf(1:2),*) date(2)
599 log_error(
"CALENDAR_CFunits2sec",*)
'units for time is invalid (day)'
600 log_error_cont(*) trim(cfunits)
601 log_error_cont(*) trim(buf)
604 read(buf(1:2),*) date(3)
609 log_error(
"CALENDAR_CFunits2sec",*)
'units for time is invalid (hour)'
610 log_error_cont(*) trim(cfunits)
611 log_error_cont(*) trim(buf)
614 read(buf(1:2),*) date(4)
619 log_error(
"CALENDAR_CFunits2sec",*)
'units for time is invalid (min)'
620 log_error_cont(*) trim(cfunits)
621 log_error_cont(*) trim(buf)
624 read(buf(1:2),*) date(5)
627 if ( len_trim(buf) /= 2 )
then
628 log_error(
"CALENDAR_CFunits2sec",*)
'units for time is invalid (sec)'
629 log_error_cont(*) trim(cfunits)
630 log_error_cont(*) trim(buf)
631 log_error_cont(*) len_trim(buf)
634 read(buf(1:2),*) date(6)
645 if (
present(startdaysec) )
then
667 character(len=27),
intent(out) :: chardate
668 integer,
intent(in) :: ymdhms(6)
669 real(
dp),
intent(in) :: subsec
671 character(len=4) :: seclen
672 character(len=4) :: minlen
673 character(len=4) :: hourlen
674 character(len=4) :: daylen
675 character(len=4) :: monthlen
679 if ( calendar_user)
then
680 write(daylen,
'(A1,I1.1,A1,I1.1)')
'I', int(log10(real(maxval(calendar_user_defined))))+1, &
681 '.', int(log10(real(maxval(calendar_user_defined))))+1
682 if( calendar_month < 10 )
then
683 write(monthlen,
'(A4)')
'I1.1'
685 write(monthlen,
'(A4)')
'I2.2'
688 write(daylen,
'(A4)')
'I2.2'
689 write(monthlen,
'(A4)')
'I2.2'
692 write(seclen,
'(A1,I1.1,A1,I1.1)')
'I', int(log10(max(
calendar_sec -1.0_dp, 1.0_dp)))+1, &
694 write(minlen,
'(A1,I1.1,A1,I1.1)')
'I', int(log10(max(
calendar_min -1.0_dp, 1.0_dp)))+1, &
696 write(hourlen,
'(A1,I1.1,A1,I1.1)')
'I', int(log10(max(
calendar_hour-1.0_dp, 1.0_dp)))+1, &
700 write(chardate,
'(I4.4,A1,'//monthlen//
',A1,'//daylen//
',A1,'//hourlen//
',A1,'//minlen//
',A1,'//seclen//
',A2,F6.3)') &
701 ymdhms(1),
'/',ymdhms(2),
'/',ymdhms(3),
' ', &
702 ymdhms(4),
':',ymdhms(5),
':',ymdhms(6),
' +', &
711 function checkleap( iyear )
714 integer,
intent(in) :: iyear
717 integer :: check4, check100, check400
720 check4 = mod(iyear,4 )
721 check100 = mod(iyear,100)
722 check400 = mod(iyear,400)
725 if( check4 == 0 ) checkleap = .true.
726 if( check100 == 0 ) checkleap = .false.
727 if( check400 == 0 ) checkleap = .true.
729 if( calendar_360days ) checkleap = .false.
730 if( calendar_365days ) checkleap = .false.
731 if( calendar_user ) checkleap = .false.
733 end function checkleap
737 subroutine calendar_ymdhms2nd( &
743 real(
dp),
intent(out) :: nd
744 integer,
intent(in) :: ymdhms(6)
745 integer,
intent(in) :: oyear
747 integer :: absday, absday_jan1
762 nd = absday - absday_jan1 + 1.0_dp
765 end subroutine calendar_ymdhms2nd
769 subroutine calendar_ymdhms2mjd( &
775 real(
dp),
intent(out) :: mjd
776 integer,
intent(in) :: ymdhms(6)
777 integer,
intent(in) :: oyear
779 integer :: y, m, mjd_day
783 .OR. ymdhms(
i_month) == 2 )
then
791 mjd_day = int( 365.25_dp * y ) &
792 + int( y/400.0_dp ) - int( y/100.0_dp ) &
793 + int( 30.59_dp * m-2 ) &
797 mjd = real(mjd_day,kind=
dp) &
803 end subroutine calendar_ymdhms2mjd
806 character(len=*),
intent(out) :: name
808 if ( calendar_360days )
then
810 elseif( calendar_365days )
then
812 elseif( calendar_user )
then
813 name =
"USER_DEFINED"