!= dc_calendar å†…ã§ä½¿ç”¨ã•ã‚Œã‚‹å†…éƒ¨å‘ã‘å®šæ•°, å¤‰æ•°, æ‰‹ç¶šãç¾¤
!= Internal parameters, variables, procedures used in "dc_calendar"
!
! Authors::   Yasuhiro MORIKAWA
! Version::   $Id: dc_calendar_internal.f90,v 1.7 2010-10-06 01:48:12 morikawa Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2009-. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]

module dc_calendar_internal
  !
  != dc_calendar å†…ã§ä½¿ç”¨ã•ã‚Œã‚‹å†…éƒ¨å‘ã‘å®šæ•°, å¤‰æ•°, æ‰‹ç¶šãç¾¤
  != Internal parameters, variables, procedures used in "dc_calendar"
  !

  use dc_calendar_types, only: DC_CAL, DC_CAL_DATE
  use dc_types, only: DP
  implicit none
  private
  public:: default_cal_set, dccaldate_normalize, &
    &      dccaltype_str, dccaldate_str2ustr, &
    &      dccaldate_str2usym, dccaldate_ym2d

  type(DC_CAL), save, target, public:: default_cal
                               ! ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®æš¦.
                               !
                               ! DCCal ã§å§‹ã¾ã‚‹æ‰‹ç¶šã®ã†ã¡,
                               ! "dc_calendar_types#DC_CAL" åž‹ã®
                               ! çœç•¥å¯èƒ½å¼•æ•°ãŒä¸Žãˆã‚‰ã‚Œãªã„å ´åˆã«ã¯ã“ã®æš¦
                               ! ãŒè¨å®šã‚‚ã—ãã¯åˆ©ç”¨ã•ã‚Œã‚‹.
                               !

  type(DC_CAL_DATE), save, target, public:: default_date
                               ! ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®æ—¥æ™‚.
                               !
                               ! DCCalDate ã§å§‹ã¾ã‚‹æ‰‹ç¶šã®ã†ã¡,
                               ! "dc_calendar_types#DC_CAL_DATE" åž‹ã®
                               ! çœç•¥å¯èƒ½å¼•æ•°ãŒä¸Žãˆã‚‰ã‚Œãªã„å ´åˆã«ã¯ã“ã®æ—¥æ™‚
                               ! ãŒè¨å®šã‚‚ã—ãã¯åˆ©ç”¨ã•ã‚Œã‚‹.
                               !

contains
  subroutine default_cal_set
    !
    ! DCCal ã§å§‹ã¾ã‚‹æ‰‹ç¶šãŒå‘¼ã³å‡ºã•ã‚Œ, "dc_calendar_types#DC_CAL" åž‹ã®
    ! å¼•æ•°ã«æš¦ã®è¨å®šãŒè¡Œã‚ã‚Œã¦ã„ãªã„å ´åˆã«ã¯, ã¾ãšã“ã®æ‰‹ç¶šã‚’å‘¼ã³å‡ºã—ã¦,
    ! ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®æš¦ "default_cal" ã‚’ã‚°ãƒ¬ã‚´ãƒªã‚ªæš¦ã¨ã—ã¦è¨å®šã™ã‚‹.
    !
    ! æ—¢ã« "default_cal" ã«æš¦ãŒè¨å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã«ã¯ã“ã®æ‰‹ç¶š
    ! å†…ã§ãã‚Œã‚’åˆ¤å®šã—ã¦ä½•ã‚‚ã›ãšã«æ‰‹ç¶šã‚’çµ‚äº†ã™ã‚‹ãŸã‚,
    ! ã“ã®æ‰‹ç¶šã¯ä½•åº¦å‘¼ã³å‡ºã—ã¦ã‚‚è‰¯ã, å‘¼ã³å‡ºã™å´ã§çŠ¶æ…‹ã®æœ‰ç„¡ã‚’
    ! ç¢ºèªã™ã‚‹å¿…è¦ã¯ãªã„.
    !
    use dc_calendar_types, only: CAL_GREGORIAN
    implicit none
    type(DC_CAL), pointer:: calp =>null()
  continue
    calp => default_cal

    if ( calp % initialized ) return

    calp % cal_type = CAL_GREGORIAN
    calp % month_in_year = 12
    calp % hour_in_day   = 24
    calp % min_in_hour   = 60
    calp % sec_in_min    = 60.0_DP
    allocate( calp % day_in_month(1:12) )
    calp % day_in_month(1:12) = &
      & (/ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 /)

    calp % initialized = .true.
    nullify( calp )
  end subroutine default_cal_set

  function dccaldate_normalize( year, month, day, hour, min, sec, cal ) result(stat)
    !
    ! æš¦æƒ…å ± cal ã«å¾“ã„, æ—¥æ™‚æƒ…å ±ã®æ£è¦åŒ–ã‚’è¡Œã†.
    ! dc_calender ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å†…éƒ¨ã§ä½¿ç”¨ã•ã‚Œã‚‹ã“ã¨ã‚’å‰æã¨ã™ã‚‹.
    ! å…·ä½“çš„ã«ã¯ä»¥ä¸‹ã®å ´åˆã«æ£è¦åŒ–ã‚’å®Ÿæ–½ã™ã‚‹.
    !
    ! * sec ãŒ cal ã§è¨å®šã•ã‚Œã‚‹ã€Œ1 åˆ†ã®ç§’æ•°ã€ã‚’è¶…ãˆã¦ã„ã‚‹.
    !   -> sec ã‚’ã€Œ1 åˆ†ã®ç§’æ•°ã€ä»¥å†…ã«ç´ã‚ã‚‹ã‚ˆã†ï¼Œå¹´æœˆæ—¥æ™‚åˆ†ã«ç¹°ã‚Šä¸Šã’ã‚‹ï¼Ž
    ! * min ãŒ cal ã§è¨å®šã•ã‚Œã‚‹ã€Œ1 æ™‚é–“ã®åˆ†æ•°ã€ã‚’è¶…ãˆã¦ã„ã‚‹.
    !   -> min ã‚’ã€Œ1 æ™‚é–“ã®åˆ†æ•°ã€ä»¥å†…ã«ç´ã‚ã‚‹ã‚ˆã†ï¼Œå¹´æœˆæ—¥æ™‚ã«ç¹°ã‚Šä¸Šã’ã‚‹ï¼Ž
    ! * hour ãŒ cal ã§è¨å®šã•ã‚Œã‚‹ã€Œ1 æ—¥ã®æ™‚é–“æ•°ã€ã‚’è¶…ãˆã¦ã„ã‚‹.
    !   -> hour ã‚’ã€Œ1 æ—¥ã®æ™‚é–“æ•°ã€ä»¥å†…ã«ç´ã‚ã‚‹ã‚ˆã†ï¼Œå¹´æœˆæ—¥ã«ç¹°ã‚Šä¸Šã’ã‚‹ï¼Ž
    ! * day ãŒ cal ã§è¨å®šã•ã‚Œã‚‹ã€Œ1 æœˆã®æ—¥æ•°ã€ã‚’è¶…ãˆã¦ã„ã‚‹.
    !   -> day ã‚’ã€Œ1 æœˆã®æ—¥æ•°ã€ä»¥å†…ã«ç´ã‚ã‚‹ã‚ˆã†ï¼Œå¹´æœˆã«ç¹°ã‚Šä¸Šã’ã‚‹ï¼Ž
    !
    ! * sec, min, hour, day ãŒè² ã®å ´åˆ.
    !   -> ãã‚Œãžã‚Œã‚’æ£ã«ã™ã‚‹ã‚ˆã†è² ã®åˆ†ã‚’ä¸Šã®ä½ã«ç¹°ã‚Šä¸Šã’ã‚‹ï¼Ž
    !
    ! * day ãŒ 0 ã®å ´åˆ.
    !   -> æ£ã«ã™ã‚‹ã‚ˆã†ä¸Šã®ä½ã«ç¹°ã‚Šä¸Šã’ã‚‹ï¼Ž
    !
    ! æ£å¸¸ã«æ£è¦åŒ–ãŒè¡Œã‚ã‚Œã‚Œã° stat ã«ã¯ DC_NOERR (=0) ãŒè¿”ã‚‹ãŒ,
    ! æ—¥æ™‚æƒ…å ±ãŒæš¦ã¨æ•´åˆçš„ã§ãªã„å ´åˆã«ã¯ã‚¨ãƒ©ãƒ¼ã‚³ãƒ¼ãƒ‰ DC_EINCONSISTCALDATE
    ! ãŒè¿”ã‚‹. æ•´åˆçš„ã§ã‚ã‚‹ã‹ã©ã†ã‹ã¯ä»¥ä¸‹ã§åˆ¤å®šã™ã‚‹.
    !
    ! * æœˆãŒ, æš¦æƒ…å ±ã«å«ã¾ã‚Œã‚‹ã€Œ1å¹´ã®æœˆæ•°ã€ã‚’
    !   æ—¢ã«è¶…ãˆã¦ã—ã¾ã£ã¦ã„ã‚‹å ´åˆ
    !
    use dc_error, only: DC_NOERR, DC_EINCONSISTCALDATE
    use dc_calendar_types, only: &
      & CAL_USER_DEFINED, &
      & CAL_CYCLIC, CAL_NOLEAP, CAL_JULIAN, CAL_GREGORIAN, CAL_360DAY
    implicit none
    integer:: stat                      ! ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹. Status.
    integer, intent(inout):: year       ! å¹´. Year.
    integer, intent(inout):: month      ! æœˆ. Month.
    integer, intent(inout):: day        ! æ—¥. Day.
    integer, intent(inout):: hour       ! æ™‚. Hour.
    integer, intent(inout):: min        ! åˆ†. Minute.
    real(DP), intent(inout):: sec       ! ç§’. Sec.
    type(DC_CAL), intent(in):: cal
                              ! æš¦æƒ…å ±ã‚’åŽã‚ãŸã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆ.
                              !
                              ! An object that stores information of
                              ! calendar.

    ! æ—¢å®šã®æš¦ã§ã® 1 ãƒ¶æœˆã®æ—¥æ•°
    ! Days in months of previously-defined calendars
    !
    integer:: day_in_month_jg
    integer, pointer:: day_in_month(:) =>null()

    ! æ—¢å®šã®æš¦ã§ã® 1 æ—¥ãƒ»æ™‚é–“ãƒ»åˆ†ã®æ™‚é–“ãƒ»åˆ†ãƒ»ç§’æ•°
    ! Hours, minutes, seconds in a day, a hour, a minute of previously-defined calendars
    !
    integer:: month_in_year   ! 1 æ—¥ã®æ™‚é–“æ•°.
                              ! Hours in a day.
    integer:: hour_in_day     ! 1 æ—¥ã®æ™‚é–“æ•°.
                              ! Hours in a day.
    integer:: min_in_hour     ! 1 æ™‚é–“ã®åˆ†æ•°.
                              ! Minutes in a hour.
    real(DP):: sec_in_min     ! 1 åˆ†ã®ç§’æ•°.
                              ! Seconds in a minute.

    ! ä½œæ¥å¤‰æ•°
    ! Work variables
    !
    real(DP):: wyear, wday, whour, wmin
    real(DP):: wdb, ychunk_e6, ychunk_e3, chunk_scale_e6, chunk_scale_e3
  continue
    stat = DC_NOERR

    ! æ—¥æ™‚ã¨æš¦ã®æ•´åˆæ€§ãƒã‚§ãƒƒã‚¯
    ! Check consistency calendar and date
    !
!!$    if ( min  > cal % min_in_hour ) stat = DC_EINCONSISTCALDATE
!!$    if ( hour > cal % hour_in_day ) stat = DC_EINCONSISTCALDATE
!!$    if ( all( day  > cal % day_in_month) ) stat = DC_EINCONSISTCALDATE
    select case( cal % cal_type )
    case( CAL_USER_DEFINED )
      if ( month > cal % month_in_year ) stat = DC_EINCONSISTCALDATE
    case default
      if ( month > 12 ) stat = DC_EINCONSISTCALDATE
    end select

    if ( stat /= DC_NOERR ) return

    ! ç§’ã€œæ—¥ã®å¤‰æ›ãƒ‘ãƒ©ãƒ¡ã‚¿ä»–ã®è¨å®š
    ! Set parameter for conversion of sec -- day, etc
    !
    month_in_year = cal % month_in_year
    hour_in_day   = cal % hour_in_day
    min_in_hour   = cal % min_in_hour
    sec_in_min    = cal % sec_in_min
    day_in_month => cal % day_in_month

    select case( cal % cal_type )
    case( CAL_JULIAN )
      chunk_scale_e6 = 4.0e+5
      ychunk_e6 = 146100000.0_DP

      chunk_scale_e3 = 4.0e+2
      ychunk_e3 = 146100.0_DP
    case( CAL_GREGORIAN )
      chunk_scale_e6 = 4.0e+5
      ychunk_e6 = 146097000.0_DP

      chunk_scale_e3 = 4.0e+2
      ychunk_e3 = 146097.0_DP
    case default
      chunk_scale_e6 = 1.0e+6
      ychunk_e6 = chunk_scale_e6 * sum( day_in_month(:) )

      chunk_scale_e3 = 1.0e+3
      ychunk_e3 = chunk_scale_e3 * sum( day_in_month(:) )
    end select

    ! å€ç²¾åº¦å®Ÿæ•°ã«ä¸€æ™‚çš„ã«æ ¼ç´
    ! Store in double precision variable temporally
    !
    wyear  = real( year, DP )
    wday   = real( day, DP )
    whour  = real( hour, DP )
    wmin   = real( min, DP )

    ! ç§’ -> åˆ†ã®ç¹°ã‚Šä¸Šã’
    ! Moving up sec -> min
    !
    if ( .not. sec < sec_in_min ) then
      wmin = wmin + aint( sec / sec_in_min )
      sec = mod( sec, sec_in_min )
    elseif ( sec < 0.0_DP ) then
      wdb = ceiling( abs(sec) / sec_in_min )
      wmin = wmin - wdb
      sec = sec + wdb * sec_in_min
    end if

    ! åˆ† -> æ™‚ã®ç¹°ã‚Šä¸Šã’
    ! Moving up min -> hour
    !
    if ( .not. wmin < min_in_hour ) then
      whour = whour + aint( wmin / min_in_hour )
      wmin = mod( wmin, real( min_in_hour, DP ) )
    elseif ( wmin < 0 ) then
      wdb = ceiling( abs(wmin) / real(min_in_hour) )
      whour = whour - wdb
      wmin = wmin + wdb * min_in_hour
    end if

    ! æ™‚ -> æ—¥ã®ç¹°ã‚Šä¸Šã’
    ! Moving up hour -> day
    !
    if ( .not. whour < hour_in_day ) then
      wday = wday + aint( whour / hour_in_day )
      whour = mod( whour, real( hour_in_day, DP ) )
    elseif ( whour < 0 ) then
      wdb = ceiling( abs(whour) / real(hour_in_day) )
      wday = wday - wdb
      whour = whour + wdb * hour_in_day
    end if

    ! æ—¥ãŒè² ã‚‚ã—ãã¯ 0 ã®å ´åˆï¼Œè² ã®éƒ¨åˆ†ã‚’å¹´ã«ç¹°ã‚Šä¸Šã’ï¼Œæ—¥ã‚’æ£ã«å¤‰æ›
    ! Negative or 0 part of day is moved up to year
    !
    if ( wday < 1.0_DP ) then
      select case( cal % cal_type )
      case( CAL_JULIAN )

        do while ( wday < 1.0_DP )

          if ( wday < - ychunk_e6 ) then
            wyear = wyear + chunk_scale_e6 * ( aint( wday / ychunk_e6 ) - 1.0_DP )
            wday = mod( wday, ychunk_e6 ) + ychunk_e6
          end if

          if ( wday < 1.0_DP ) then
            wyear = wyear + chunk_scale_e3 * ( aint( wday / ychunk_e3 ) - 1.0_DP )
            wday = mod( wday, ychunk_e3 ) + ychunk_e3
          end if

        end do

      case( CAL_GREGORIAN )

        do while ( wday < 1.0_DP )

          if ( wday < - ychunk_e6 ) then
            wyear = wyear + chunk_scale_e6 * ( aint( wday / ychunk_e6 ) - 1.0_DP )
            wday = mod( wday, ychunk_e6 ) + ychunk_e6
          end if

          if ( wday < 1.0_DP ) then
            wyear = wyear + chunk_scale_e3 * ( aint( wday / ychunk_e3 ) - 1.0_DP )
            wday = mod( wday, ychunk_e3 ) + ychunk_e3
          end if

        end do

      case default

        do while ( wday < 1.0_DP )

          if ( wday < - ychunk_e6 ) then
            wyear = wyear + chunk_scale_e6 * ( aint( wday / ychunk_e6 ) - 1.0_DP )
            wday = mod( wday, ychunk_e6 ) + ychunk_e6
          end if

          if ( wday < 1.0_DP ) then
            wyear = wyear + chunk_scale_e3 * ( aint( wday / ychunk_e3 ) - 1.0_DP )
            wday = mod( wday, ychunk_e3 ) + ychunk_e3
          end if

        end do

      end select

    end if

    ! æ—¥ -> å¹´æœˆã®ç¹°ã‚Šä¸Šã’
    ! Moving up day -> year and month
    !
    select case( cal % cal_type )
    case( CAL_JULIAN )

      if ( wday > ychunk_e6 ) then
        wyear = wyear + chunk_scale_e6 * aint( wday / ychunk_e6 )
        wday = mod( wday, ychunk_e6 )
      end if

      if ( wday > ychunk_e3 ) then
        wyear = wyear + chunk_scale_e3 * aint( wday / ychunk_e3 )
        wday = mod( wday, ychunk_e3 )
      end if

      do
        if ( month == 2 ) then
          if ( mod( wyear, 4.0_DP ) == 0 ) then
            day_in_month_jg = 29
          else
            day_in_month_jg = 28
          end if
        else
          day_in_month_jg = day_in_month(month)
        end if

        if ( .not. wday > day_in_month_jg ) exit

        wday = wday - day_in_month_jg
        month = month + 1
        if ( month > month_in_year ) then
          month = 1
          wyear = wyear + 1
        end if
      end do

    case( CAL_GREGORIAN )

      if ( wday > ychunk_e6 ) then
        wyear = wyear + chunk_scale_e6 * aint( wday / ychunk_e6 )
        wday = mod( wday, ychunk_e6 )
      end if

      if ( wday > ychunk_e3 ) then
        wyear = wyear + chunk_scale_e3 * aint( wday / ychunk_e3 )
        wday = mod( wday, ychunk_e3 )
      end if

      do
        if ( month == 2 ) then
          if ( mod( wyear, 400.0_DP ) == 0 ) then
            day_in_month_jg = 29
          elseif ( mod( wyear, 100.0_DP ) == 0 ) then
            day_in_month_jg = 28
          elseif ( mod( wyear, 4.0_DP ) == 0 ) then
            day_in_month_jg = 29
          else
            day_in_month_jg = 28
          end if
        else
          day_in_month_jg = day_in_month(month)
        end if

        if ( .not. wday > day_in_month_jg ) exit

        wday = wday - day_in_month_jg
        month = month + 1
        if ( month > month_in_year ) then
          month = 1
          wyear = wyear + 1
        end if
      end do

    case default

      if ( wday > ychunk_e6 ) then
        wyear = wyear + chunk_scale_e6 * aint( wday / ychunk_e6 )
        wday = mod( wday, ychunk_e6 )
      end if

      if ( wday > ychunk_e3 ) then
        wyear = wyear + chunk_scale_e3 * aint( wday / ychunk_e3 )
        wday = mod( wday, ychunk_e3 )
      end if

      do while ( wday > day_in_month(month) )
        wday = wday - day_in_month(month)
        month = month + 1
        if ( month > month_in_year ) then
          month = 1
          wyear = wyear + 1
        end if
      end do

    end select

    ! æ•´æ•°ã«æˆ»ã™
    ! Return to integer
    !
    year  = wyear
    day   = wday
    hour  = whour
    min   = wmin

  end function dccaldate_normalize

  function dccaldate_ym2d( year, month, day, cal, day_of_year ) result(stat)
    !
    ! æš¦æƒ…å ± cal ã«å¾“ã„, æœˆæ—¥ã‚’ãã®å¹´ãŒå§‹ã¾ã£ãŸæ™‚ã‹ã‚‰ã®é€šæ—¥ã«å¤‰æ›ã™ã‚‹.
    ! çµæžœã¯å€ç²¾åº¦å®Ÿæ•°ã¨ã—ã¦ *day_of_year* ã«è¿”ã‚‹.
    ! dccaldate_normalize ã«ã‚ˆã£ã¦æ£è¦åŒ–ã—ãŸå¾Œã«å‘¼ã³å‡ºã™ã“ã¨.
    !
    use dc_error, only: DC_NOERR, DC_EINCONSISTCALDATE
    use dc_calendar_types, only: &
      & CAL_USER_DEFINED, &
      & CAL_CYCLIC, CAL_NOLEAP, CAL_JULIAN, CAL_GREGORIAN, CAL_360DAY
    implicit none
    integer:: stat                      ! ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹. Status.
    integer, intent(in):: year          ! å¹´. Year.
    integer, intent(in):: month         ! æœˆ. Month.
    integer, intent(in):: day           ! æ—¥. Day.
    real(DP), intent(out):: day_of_year ! å¹´å§‹ã‹ã‚‰ã®é€šæ—¥. Day of year
    type(DC_CAL), intent(in):: cal
                              ! æš¦æƒ…å ±ã‚’åŽã‚ãŸã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆ.
                              !
                              ! An object that stores information of
                              ! calendar.

    ! ä½œæ¥å¤‰æ•°
    ! Work variables
    !
    integer:: i

  continue
    stat = DC_NOERR

    ! æ—¥æ™‚ã¨æš¦ã®æ•´åˆæ€§ãƒã‚§ãƒƒã‚¯
    ! Check consistency calendar and date
    !
!!$    if ( min  > cal % min_in_hour ) stat = DC_EINCONSISTCALDATE
!!$    if ( hour > cal % hour_in_day ) stat = DC_EINCONSISTCALDATE
!!$    if ( all( day  > cal % day_in_month) ) stat = DC_EINCONSISTCALDATE
    select case( cal % cal_type )
    case( CAL_USER_DEFINED )
      if ( month > cal % month_in_year ) stat = DC_EINCONSISTCALDATE
    case default
      if ( month > 12 ) stat = DC_EINCONSISTCALDATE
    end select

    if ( stat /= DC_NOERR ) return

    ! å€ç²¾åº¦å®Ÿæ•°ã«ä¸€æ™‚çš„ã«æ ¼ç´
    ! Store in double precision variable temporally
    !
    day_of_year  = real( day, DP )

    ! å¹´æœˆ -> æ—¥ ã®ç¹°ã‚Šä¸‹ã’
    ! Moving doun year and month -> day
    !
    select case( cal % cal_type )
    case( CAL_JULIAN )

      do i = 1, month - 1
        if ( i == 2 ) then
          if ( mod( year, 4 ) == 0 ) then
            day_of_year = day_of_year + 29
          else
            day_of_year = day_of_year + 28
          end if
        else
          day_of_year = day_of_year + cal % day_in_month(i)
        end if
      end do

    case( CAL_GREGORIAN )

      do i = 1, month - 1
        if ( i == 2 ) then
          if ( mod( year, 400 ) == 0 ) then
            day_of_year = day_of_year + 29
          elseif ( mod( year, 100 ) == 0 ) then
            day_of_year = day_of_year + 28
          elseif ( mod( year, 4 ) == 0 ) then
            day_of_year = day_of_year + 29
          else
            day_of_year = day_of_year + 28
          end if
        else
          day_of_year = day_of_year + cal % day_in_month(i)
        end if

      end do

    case default

      do i = 1, month - 1
        day_of_year = day_of_year + cal % day_in_month(i)
      end do

    end select

  end function dccaldate_ym2d

  function dccaltype_str( cal_type ) result(str)
    !
    ! æ•´æ•°åž‹ã®æš¦ã‚¿ã‚¤ãƒ— *cal_type* ã‚’æ–‡å—åˆ— *str* ã«å¤‰æ›ã™ã‚‹.
    ! ä¸æ£ãª *cal_type* ã®å ´åˆã¯ç©ºæ–‡å—ãŒè¿”ã‚‹.
    !
    use dc_calendar_types, only: &
      & CAL_USER_DEFINED, &
      & CAL_CYCLIC, CAL_NOLEAP, CAL_JULIAN, CAL_GREGORIAN, CAL_360DAY
    use dc_types, only: TOKEN
    implicit none
    character(TOKEN):: str
    integer, intent(in):: cal_type

    ! ä½œæ¥å¤‰æ•°
    ! Work variables
    !
  continue
    select case( cal_type )
    case(CAL_USER_DEFINED) ; str = 'user_defined'
    case(CAL_CYCLIC)       ; str = 'cyclic      '
    case(CAL_NOLEAP)       ; str = 'noleap      '
    case(CAL_JULIAN)       ; str = 'julian      '
    case(CAL_GREGORIAN)    ; str = 'gregorian   '
    case(CAL_360DAY)       ; str = '360day      '
    case default           ; str = '            '
    end select
  end function dccaltype_str

  function dccaldate_str2ustr(str) result(unit)
    !
    ! å¼•æ•° *str* ã«ä¸Žãˆã‚‰ã‚ŒãŸæ–‡å—åˆ—ã‚’è§£é‡ˆã—, æ—¥æ™‚ã®å˜ä½ã‚’ *unit* ã«è¿”ã™.
    ! ãã‚Œãžã‚Œä»¥ä¸‹ã®æ–‡å—åˆ—ãŒæ—¥æ™‚ã®å˜ä½ã¨ã—ã¦è§£é‡ˆã•ã‚Œã‚‹.
    ! å¤§æ–‡å—ã¨å°æ–‡å—ã¯åŒºåˆ¥ã•ã‚Œãªã„.
    ! è¿”ã‚‹æ–‡å—åˆ—ã¯ä»¥ä¸‹ã®æ–‡å—åž‹ã®é…åˆ—ã®å…ˆé ã®æ–‡å—åˆ—ã¨ãªã‚‹.
    ! (ä¾‹: *str* ã« 'hrs.' ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆ, dc_calendar_types#UNIT_HOUR
    ! é…åˆ—ã®å…ˆé ã®æ–‡å—åˆ— UNIT_HOUR(1) ãŒè¿”ã‚‹.)
    !
    ! å¹´         :: dc_calendar_types#UNIT_YEAR
    ! æœˆ         :: dc_calendar_types#UNIT_MONTH
    ! æ—¥         :: dc_calendar_types#UNIT_DAY
    ! æ™‚         :: dc_calendar_types#UNIT_HOUR
    ! åˆ†         :: dc_calendar_types#UNIT_MIN
    ! ç§’         :: dc_calendar_types#UNIT_SEC
    !
    ! ã“ã‚Œã‚‰ã«è©²å½“ã—ãªã„æ–‡å—åˆ—ã‚’ *str* ã«ä¸ŽãˆãŸå ´åˆ, ç©ºæ–‡å—ãŒè¿”ã‚‹.
    !
    use dc_types, only: TOKEN
    use dc_calendar_types, only: UNIT_YEAR, UNIT_MONTH, UNIT_DAY, &
      & UNIT_HOUR, UNIT_MIN, UNIT_SEC
    use dc_string, only: StriEq
    implicit none
    character(*), intent(in):: str
    character(TOKEN):: unit
    integer :: unit_str_size, i
  continue
    unit = adjustl(str)

    unit_str_size = size(UNIT_SEC)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_SEC(i)))) then
        unit = UNIT_SEC(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_MIN)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MIN(i)))) then
        unit = UNIT_MIN(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_HOUR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_HOUR(i)))) then
        unit = UNIT_HOUR(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_DAY)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_DAY(i)))) then
        unit = UNIT_DAY(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_MONTH)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MONTH(i)))) then
        unit = UNIT_MONTH(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_YEAR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_YEAR(i)))) then
        unit = UNIT_YEAR(1)
        return
      end if
    end do

    unit = ''

  end function dccaldate_str2ustr

  function dccaldate_str2usym(str) result(symbol)
    !
    ! å¼•æ•° *str* ã«ä¸Žãˆã‚‰ã‚ŒãŸæ–‡å—åˆ—ã‚’è§£é‡ˆã—, æ—¥æ™‚ã®å˜ä½ã‚’ç¤ºã™
    ! æ•´æ•° *symbol* ã‚’è¿”ã™. ãã‚Œãžã‚Œä»¥ä¸‹ã®æ–‡å—åˆ—ãŒæ—¥æ™‚ã®å˜ä½ã¨ã—ã¦è§£é‡ˆã™ã‚‹.
    ! å¤§æ–‡å—ã¨å°æ–‡å—ã¯åŒºåˆ¥ã—ãªã„.
    !
    ! å¹´         :: dc_calendar_types#UNIT_YEAR
    ! æœˆ         :: dc_calendar_types#UNIT_MONTH
    ! æ—¥         :: dc_calendar_types#UNIT_DAY
    ! æ™‚         :: dc_calendar_types#UNIT_HOUR
    ! åˆ†         :: dc_calendar_types#UNIT_MIN
    ! ç§’         :: dc_calendar_types#UNIT_SEC
    !
    ! è¿”ã‚‹ã‚·ãƒ³ãƒœãƒ« (æ•´æ•°åž‹) ã¯ä»¥ä¸‹ã®é€šã‚Š.
    !
    ! å¹´         :: dc_calendar_types#UNIT_SYMBOL_YEAR
    ! æœˆ         :: dc_calendar_types#UNIT_SYMBOL_MONTH
    ! æ—¥         :: dc_calendar_types#UNIT_SYMBOL_DAY
    ! æ™‚         :: dc_calendar_types#UNIT_SYMBOL_HOUR
    ! åˆ†         :: dc_calendar_types#UNIT_SYMBOL_MIN
    ! ç§’         :: dc_calendar_types#UNIT_SYMBOL_SEC
    !
    ! ã“ã‚Œã‚‰ã«è©²å½“ã—ãªã„æ–‡å—åˆ—ã‚’ *str* ã«ä¸ŽãˆãŸå ´åˆ,
    ! dc_calendar_types#UNIT_SYMBOL_ERR ãŒè¿”ã‚‹.
    !
    use dc_types, only: TOKEN
    use dc_calendar_types, only: UNIT_YEAR, UNIT_MONTH, UNIT_DAY, &
      & UNIT_HOUR, UNIT_MIN, UNIT_SEC, &
      & UNIT_SYMBOL_YEAR, UNIT_SYMBOL_MONTH, UNIT_SYMBOL_DAY, &
      & UNIT_SYMBOL_HOUR, UNIT_SYMBOL_MIN, UNIT_SYMBOL_SEC, &
      & UNIT_SYMBOL_ERR
    use dc_string, only: StriEq
    implicit none
    character(*), intent(in):: str
    integer:: symbol
    integer:: unit_str_size, i
    character(TOKEN):: unit
  continue
    unit = adjustl(str)

    unit_str_size = size(UNIT_SEC)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_SEC(i)))) then
        symbol = UNIT_SYMBOL_SEC
        return
      end if
    end do

    unit_str_size = size(UNIT_MIN)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MIN(i)))) then
        symbol = UNIT_SYMBOL_MIN
        return
      end if
    end do

    unit_str_size = size(UNIT_HOUR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_HOUR(i)))) then
        symbol = UNIT_SYMBOL_HOUR
        return
      end if
    end do

    unit_str_size = size(UNIT_DAY)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_DAY(i)))) then
        symbol = UNIT_SYMBOL_DAY
        return
      end if
    end do

    unit_str_size = size(UNIT_MONTH)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MONTH(i)))) then
        symbol = UNIT_SYMBOL_MONTH
        return
      end if
    end do

    unit_str_size = size(UNIT_YEAR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_YEAR(i)))) then
        symbol = UNIT_SYMBOL_YEAR
        return
      end if
    end do

    symbol = UNIT_SYMBOL_ERR

  end function dccaldate_str2usym

end module dc_calendar_internal