!== dc_date_types#DC_DATETIME, dc_date_types#DC_DIFFTIME åž‹å¤‰æ•°ã®ç”Ÿæˆ
!
! Authors::   Yasuhiro MORIKAWA, Eizi TOYODA
! Version::   $Id: dcdatetimecreate.f90,v 1.3 2010-04-11 14:13:51 morikawa Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2000-2006. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]
!
! ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã§æä¾›ã•ã‚Œã‚‹æ‰‹ç¶šãç¾¤ã¯ dc_date ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã«ã¦æä¾›ã•ã‚Œã¾ã™ã€‚
!

subroutine DCDateTimeCreate1(time, &
  & year, mon, day, hour, min, sec, &
  & zone, zone_hour, zone_min, caltype, caltype_str, day_seconds, &
  & sclyear, sclmon, sclday, sclsec, err)
  !
  ! dc_date_types#DC_DATETIME åž‹å¤‰æ•°ã®ç”Ÿæˆã‚’è¡Œã„ã¾ã™.
  ! å¼•æ•° *year*, *mon*, *day*, *hour*, *min*, *sec* ã®å…¨ã¦ã‚’ä¸Žãˆãªã„å ´åˆ,
  ! ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ãŒå‘¼ã°ã‚ŒãŸéš›ã®æ™‚åˆ»ãŒä½¿ç”¨ã•ã‚Œã¾ã™.
  !
  ! å¼•æ•° *caltype* ã«ã¯æš¦æ³•ã‚’è¨å®šã—ã¾ã™.
  ! dc_date_types#CAL_CYCLIC, dc_date_types#CAL_NOLEAP,
  ! dc_date_types#CAL_JULIAN, dc_date_types#CAL_GREGORIAN
  ! ã®ã„ã¥ã‚Œã‹ã‚’ä¸Žãˆã¦ãã ã•ã„. å¼•æ•° *caltype* ã‚’æŒ‡å®šã—ãªã„å ´åˆ, æš¦æ³•ã¯
  ! dc_date_types#CAL_GREGORIAN ã«è¨å®šã•ã‚Œã¾ã™.
  ! æš¦æ³•ã¯ *caltype_str* ã«æ–‡å—åˆ—ã‚’ä¸Žãˆã‚‹ã“ã¨ã§ã‚‚æŒ‡å®šå¯èƒ½ã§ã™.
  ! ä¸Šè¨˜ã®æš¦æ³•ã«å¯¾å¿œã™ã‚‹æ–‡å—åˆ—ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™. (å¤§æ–‡å—å°æ–‡å—ã¯åŒºåˆ¥ã—ã¾ã›ã‚“)
  !
  ! dc_date_types#CAL_CYCLIC    :: cyclic
  ! dc_date_types#CAL_NOLEAP    :: noleap
  ! dc_date_types#CAL_JULIAN    :: julian
  ! dc_date_types#CAL_GREGORIAN :: gregorian
  !
  ! å¼•æ•° *zone* ã«ã¯ UTC ã‹ã‚‰ã®æ™‚å·®ã‚’è¨å®šã—ã¾ã™.
  ! '+09:00' ã‚„ '-13:00' ã®ã‚ˆã†ã«æ™‚å·®ã‚’ 6 æ–‡å—ã§æŒ‡å®šã—ã¦ãã ã•ã„.
  ! å¼•æ•° *zone* ã‚’æŒ‡å®šã—ãªã„å ´åˆ, date_and_time çµ„ã¿è¾¼ã¿ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³
  ! ã«ã‚ˆã£ã¦å¾—ã‚‰ã‚Œã‚‹æ™‚å·®ã‚’è¨å®šã—ã¾ã™.
  ! æ™‚å·®ã¯ *zone_hour* ã¾ãŸã¯ *zone_min* ã«æ•´æ•°åž‹ã‚’ä¸Žãˆã‚‹ã“ã¨ã§ã‚‚
  ! æŒ‡å®šå¯èƒ½ã§ã™.
  !
  ! å¼•æ•° *day_seconds* ã«ã¯ 1 æ—¥ä½•ç§’ã‹ã‚’è¨å®šã—ã¾ã™. ã“ã®å¼•æ•°ã‚’
  ! æŒ‡å®šã—ãªã„å ´åˆ, dc_date_types#day_seconds ã®å€¤ãŒç”¨ã„ã‚‰ã‚Œã¾ã™.
  ! dc_date_types#day_seconds ã¯ SetSecOfDay ã§å¤‰æ›´å¯èƒ½ã§ã™.
  !
  ! å¼•æ•° *caltype* ãŠã‚ˆã³, *zone* ã«ä¸é©åˆ‡ãªå€¤ãŒä¸Žãˆã‚‰ã‚ŒãŸå ´åˆ,
  ! ã‚¨ãƒ©ãƒ¼ã‚’ç™ºç”Ÿã•ã›ã¾ã™.
  ! å¼•æ•° *err* ã‚’ä¸Žãˆã¦ã„ã‚‹å ´åˆã«ã¯ *err* ã« .true. ãŒè¿”ã‚Š,
  ! ãƒ—ãƒã‚°ãƒ©ãƒ ã¯ç¶šè¡Œã—ã¾ã™.
  !

  use dc_date_generic, only: DCDiffTimeCreate, &
    & ValidCaltype, ValidZone, toChar
  use dc_date_internal, only: dcdate_set_day_seconds_scl
  use dc_date_types, only: DC_DATETIME, DC_DIFFTIME, &
    & caltype_default => caltype, &
    & flag_set_day_seconds_scl, day_seconds_scl, &
    & CYCLIC_MDAYS, CAL_NOLEAP, CAL_JULIAN, CAL_CYCLIC, CAL_GREGORIAN, &
    & MIN_SECONDS, HOUR_SECONDS, FOUR_YEARS, YEAR_MONTHS
  use dc_error, only: StoreError, DC_EBADCALTYPE, DC_EBADTIMEZONE, DC_NOERR
  use dc_message, only: MessageNotify
  use dc_trace, only: BeginSub, EndSub
  use dc_present, only: present_select
  use dc_string, only: LChar, CPrintf
  use dc_scaledsec, only: DC_SCALED_SEC, &
    & assignment(=), DCScaledSecPutLine, &
    & operator(==), operator(>), operator(<), operator(>=), operator(<=), &
    & operator(+), operator(-), operator(*), operator(/), mod, modulo, &
    & abs, int, sign, floor, DCScaledSecPutLine
  use dc_types,      only: DP, STRING, TOKEN
  implicit none
  type(DC_DATETIME), intent(out) :: time
  integer, intent(in), optional:: year ! å¹´
  integer, intent(in), optional:: mon  ! æœˆ
  integer, intent(in), optional:: day  ! æ—¥
  integer, intent(in), optional:: hour ! æ™‚
  integer, intent(in), optional:: min  ! åˆ†
  real(DP),intent(in), optional:: sec  ! ç§’
  character(*), intent(in), optional :: zone ! UTC ã‹ã‚‰ã®æ™‚å·®
  integer, intent(in), optional :: zone_hour ! UTC ã‹ã‚‰ã®æ™‚å·® (æ™‚)
  integer, intent(in), optional :: zone_min  ! UTC ã‹ã‚‰ã®æ™‚å·® (åˆ†)
  integer, intent(in), optional:: caltype ! æš¦æ³•
  character(*), intent(in), optional:: caltype_str ! æš¦æ³• (æ–‡å—åž‹ã«ã‚ˆã‚‹æŒ‡å®š)
  real(DP),intent(in), optional:: day_seconds  ! 1 æ—¥ã®ç§’æ•°
  type(DC_SCALED_SEC), intent(in), optional:: sclyear ! å¹´ (DC_SCALED_SEC åž‹)
  type(DC_SCALED_SEC), intent(in), optional:: sclmon  ! æœˆ (DC_SCALED_SEC åž‹)
  type(DC_SCALED_SEC), intent(in), optional:: sclday  ! æ—¥ (DC_SCALED_SEC åž‹)
  type(DC_SCALED_SEC), intent(in), optional:: sclsec  ! ç§’ (DC_SCALED_SEC åž‹)
  logical, intent(out), optional:: err

  real(DP):: gcsec
  integer :: gcday, gcmon, gcyear
  real(DP):: essec, esds
  integer :: esday
  type(DC_SCALED_SEC):: iday, imon, month, iyear, century, isec
  character(6) :: izone
  integer, parameter:: year_default = 0, mon_default = 1
  integer, parameter:: day_default = 1
  integer, parameter:: sec_default = 0
  logical :: current_time_used
  type(DC_DIFFTIME):: zonediff
  character(TOKEN):: zone_str
  integer :: stat, cause_i
  character(STRING) :: cause_c
  character(*), parameter :: subname = 'DCDateTimeCreate1'
continue
  current_time_used = .not. present(year) &
    & .and. .not. present(mon) &
    & .and. .not. present(day) &
    & .and. .not. present(hour) &
    & .and. .not. present(min) &
    & .and. .not. present(sec) &
    & .and. .not. present(sclyear) &
    & .and. .not. present(sclmon) &
    & .and. .not. present(sclday) &
    & .and. .not. present(sclsec)
  call BeginSub(subname, 'current_time_used=<%y>', l=(/current_time_used/))
  stat = DC_NOERR
  cause_i = DC_NOERR
  cause_c = ''

  if ( present(day_seconds) ) then
    time % day_seconds = day_seconds
  else
    if ( .not. flag_set_day_seconds_scl ) call dcdate_set_day_seconds_scl
    time % day_seconds = day_seconds_scl
  end if

  call get_current_time(gcyear, gcmon, gcday, gcsec, izone) ! (out)
  iyear = gcyear
  imon = gcmon
  iday = gcday
  isec = gcsec

  if (.not. current_time_used) then
    if ( present(zone_hour) .or. present(zone_min) ) then
      call DCDiffTimeCreate( zonediff, &     ! (out)
        & hour = zone_hour, min = zone_min ) ! (in)
      zone_str = toChar(zonediff)
      if ( zone_str(1:1) == '-' ) then
        izone(1:1) = '-'
      else
        izone(1:1) = '+'
      end if
      izone(2:6) = zone_str(13:17)
    end if
    if (present(zone)) then
      izone = zone
    end if
    if ( .not. ValidZone(izone)) then
      stat = DC_EBADTIMEZONE
      cause_c = izone
      if (present(err)) then
        call MessageNotify('W', subname, &
          & 'zone=<%c> is invalid.', &
          & c1=trim(izone))
      else
        goto 999
      end if
    end if

    if ( present(sclsec) ) then
      isec = sclsec
    elseif( present(sec) ) then
      isec = sec
    else
      isec = sec_default
    end if
    if (present(min)) then
      isec = isec + min * MIN_SECONDS
    end if
    if (present(hour)) then
      isec = isec + hour * HOUR_SECONDS
    end if

    if ( present(sclday) ) then
      iday = sclday
    elseif( present(day) ) then
      iday = day
    else
      iday = day_default
    end if

    if ( present(sclday) ) then
      iday = sclday
    elseif( present(day) ) then
      iday = day
    else
      iday = day_default
    end if
    iday = iday + floor(isec / time % day_seconds)

    if ( present(sclmon) ) then
      imon = sclmon
    elseif( present(mon) ) then
      imon = mon
    else
      imon = mon_default
    end if

    if ( present(sclyear) ) then
      iyear = sclyear
    elseif( present(year) ) then
      iyear = year
    else
      iyear = year_default
    end if
  end if

  time % zone = izone
  time % sec = modulo(isec, time % day_seconds)
  time % caltype = caltype_default
  if (present(caltype_str)) then
    select case( LChar(trim(caltype_str)) )
    case('cyclic')
      time % caltype = CAL_CYCLIC
    case('noleap')
      time % caltype = CAL_NOLEAP
    case('julian')
      time % caltype = CAL_JULIAN
    case('gregorian')
      time % caltype = CAL_GREGORIAN
    case('')
      time % caltype = CAL_GREGORIAN
    case default
      stat = DC_EBADCALTYPE
      cause_i = 0
      call MessageNotify('W', subname, &
        & 'caltype=<%c> is invalid calender type.', &
        & c1 = trim(caltype_str) )
      if ( .not. present(err) ) then
        goto 999
      end if
    end select
  end if

  if (present(caltype)) then
    if (ValidCaltype(caltype)) then
      time % caltype = caltype
    else
      stat = DC_EBADCALTYPE
      cause_i = caltype
      if (present(err)) then
        call MessageNotify('W', subname, &
          & 'caltype=<%d> is invalid calender type.', &
          & i=(/caltype/))
      else
        goto 999
      end if
    end if
  end if
  if (time % caltype == CAL_CYCLIC) then
    time % day = int( iday + imon * CYCLIC_MDAYS )
    goto 999
  endif
  month = modulo(imon - 3, YEAR_MONTHS) + 3
  iyear = iyear + int( (imon - month) / YEAR_MONTHS )
  iday = iday + int( (month * 306 - 914) / 10 )
  if (time % caltype == CAL_NOLEAP) then
    time % day = iday + iyear * 365 + 90
  else
    iday = iday + int( (iyear * FOUR_YEARS - modulo(iyear * FOUR_YEARS, 4)) / 4 )
    if (time % caltype == CAL_JULIAN .or. iday < 640116) then
      time % day = iday + 91
    else
      century = (iyear - modulo(iyear, 100)) / 100 + 1
      time % day = iday - int( (century * 3 - modulo(century * 3, 4)) / 4 ) + 93
    endif
  endif

999 continue
  call StoreError(stat, subname, err, cause_c, cause_i)
  esday = time % day ; essec = time % sec ; esds = time % day_seconds
  call EndSub(subname, 'time (caltype=%d, day=%d, sec=%f, zone=%c, day_seconds=%f)', &
    & i=(/time % caltype, esday/), d=(/essec, esds/), &
    & c1=trim(time % zone))

  contains
    subroutine get_current_time(jyear, jmon, jday, jsec, jzone)
      !
      ! date_and_time çµ„ã¿è¾¼ã¿ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’ç”¨ã„ã¦, ç¾åœ¨
      ! æ™‚åˆ»ã¨ UTC ã‹ã‚‰ã®æ™‚å·®ã‚’è¿”ã—ã¾ã™.
      !
      use dc_types, only: DP
      use dc_string, only: StoD
      implicit none
      integer, intent(out) :: jyear, jmon, jday
      real(DP), intent(out) :: jsec
      character(*), intent(out) :: jzone

      integer :: date_time_values(1:8)
      character(5)  :: zone_raw
    continue

      call date_and_time(zone=zone_raw, values=date_time_values)

      jzone = zone_raw(1:3) // ":" // zone_raw(4:5)

      jyear = date_time_values(1)
      jmon  = date_time_values(2)
      jday  = date_time_values(3)
      jsec  = real(date_time_values(5), DP) * HOUR_SECONDS &
        &     + real(date_time_values(6), DP) * MIN_SECONDS &
        &     + real(date_time_values(7), DP)

    end subroutine get_current_time

end subroutine DCDateTimeCreate1

subroutine DCDiffTimeCreate1(diff, &
  & year, mon, day, hour, min, sec, day_seconds, nondim, &
  & sclyear, sclmon, sclday, sclsec )
  !
  ! dc_date_types#DC_DIFFTIME åž‹å¤‰æ•°ã®ç”Ÿæˆã‚’è¡Œã„ã¾ã™.
  ! å¼•æ•° year, mon, day, hour, min, sec, nondim ã‚’ä¸Žãˆãªã„å ´åˆ,
  ! 0 ãŒä¸Žãˆã‚‰ã‚ŒãŸã“ã¨ã«ãªã‚Šã¾ã™.
  !
  ! å¼•æ•° *day_seconds* ã«ã¯ 1 æ—¥ä½•ç§’ã‹ã‚’è¨å®šã—ã¾ã™. ã“ã®å¼•æ•°ã‚’
  ! æŒ‡å®šã—ãªã„å ´åˆ, dc_date_types#day_seconds ã®å€¤ãŒç”¨ã„ã‚‰ã‚Œã¾ã™.
  ! dc_date_types#day_seconds ã¯ SetSecOfDay ã§å¤‰æ›´å¯èƒ½ã§ã™.
  !
  use dc_date_internal, only: dcdate_normalize
  use dc_date_generic, only: ValidCaltype
  use dc_date_types, only: DC_DIFFTIME, &
    & day_seconds_default => day_seconds, &
    & MIN_SECONDS, HOUR_SECONDS, YEAR_MONTHS
  use dc_message, only: MessageNotify
  use dc_trace, only: BeginSub, EndSub, Debug
  use dc_present, only: present_select
  use dc_scaledsec, only: DC_SCALED_SEC, &
    & assignment(=), DCScaledSecPutLine, &
    & operator(==), operator(>), operator(<), operator(>=), operator(<=), &
    & operator(+), operator(-), operator(*), operator(/), mod, modulo, &
    & abs, int, sign, floor
  use dc_string, only: CPrintf
  use dc_types,      only: DP, STRING
  implicit none
  type(DC_DIFFTIME), intent(out) :: diff
  integer,  intent(in), optional:: year ! å¹´. Year
  integer,  intent(in), optional:: mon  ! æœˆ. Month
  integer,  intent(in), optional:: day  ! æ—¥. Day
  integer,  intent(in), optional:: hour ! æ™‚. Hour
  integer,  intent(in), optional:: min  ! åˆ†. Minute
  real(DP), intent(in), optional:: sec  ! ç§’. Second
  real(DP), intent(in), optional:: day_seconds  ! 1 æ—¥ã®ç§’æ•°
  real(DP), intent(in), optional:: nondim  ! ç„¡æ¬¡å…ƒæ™‚é–“. Nondimensional time
  type(DC_SCALED_SEC), intent(in), optional:: sclyear ! å¹´ (DC_SCALED_SEC åž‹)
  type(DC_SCALED_SEC), intent(in), optional:: sclmon  ! æœˆ (DC_SCALED_SEC åž‹)
  type(DC_SCALED_SEC), intent(in), optional:: sclday  ! æ—¥ (DC_SCALED_SEC åž‹)
  type(DC_SCALED_SEC), intent(in), optional:: sclsec  ! ç§’ (DC_SCALED_SEC åž‹)

  type(DC_SCALED_SEC):: iyear, imon, iday, ihour, imin, isec
  integer, parameter:: year_default = 0, mon_default = 0
  integer, parameter:: day_default = 0, hour_default = 0, min_default = 0
  integer, parameter:: sec_default = 0
  real(DP):: essec, esds
  integer :: esmon, esday
  character(STRING):: endsub_msb
  logical:: dbg_mode
  character(*), parameter :: subname = 'DCDiffTimeCreate1'
continue
  call BeginSub(subname)

  if ( present(nondim) ) then
    diff % nondim_flag = .true.
    diff % mon = 0
    diff % day = 0
    diff % sec = nondim
    goto 999
  else
    diff % nondim_flag = .false.
  end if

  if ( present(sclyear) ) then
    iyear = sclyear
  elseif( present(year) ) then
    iyear = year
  else
    iyear = year_default
  end if

  if ( present(sclmon) ) then
    imon = sclmon
  elseif( present(mon) ) then
    imon = mon
  else
    imon = mon_default
  end if

  if ( present(sclday) ) then
    iday = sclday
  elseif( present(day) ) then
    iday = day
  else
    iday = day_default
  end if

  ihour = present_select(.false., hour_default, hour)
  imin  = present_select(.false., min_default, min)

  if ( present(sclsec) ) then
    isec = sclsec
  elseif( present(sec) ) then
    isec = sec
  else
    isec = sec_default
  end if

  diff % mon = iyear * YEAR_MONTHS + imon
  diff % day = iday
  diff % sec =   ihour * HOUR_SECONDS &
    &          + imin  * MIN_SECONDS &
    &          + isec

  if( present(day_seconds) ) then
    diff % day_seconds = day_seconds
  else
    diff % day_seconds = day_seconds_default
  end if

  call dcdate_normalize(diff % day, diff % sec, diff % day_seconds, diff % nondim_flag)

999 continue
  call Debug( dbg_mode )
  if ( dbg_mode ) then
    esmon = diff % mon ; esday = diff % day
    essec = diff % sec ; esds = diff % day_seconds
    endsub_msb = &
      & CPrintf( 'mon=%d, day=%d, sec=%f, day_seconds=%f, nondim_flag=%b', &
      &          i = (/ esmon, esday /), d = (/ essec, esds /), &
      &          l = (/ diff % nondim_flag /) )
  else
    endsub_msb = ''
  end if
  call EndSub(subname, 'diff (%c)', c1 = trim(endsub_msb) )
end subroutine DCDiffTimeCreate1

subroutine DCDiffTimeCreate2D(diff, value, unit, unit_symbol, err)
  !
  ! dc_date_types#DC_DIFFTIME åž‹å¤‰æ•°ã®ç”Ÿæˆã‚’è¡Œã„ã¾ã™.
  ! å¼•æ•° *value* ã«æ•°å€¤ã‚’, *unit* ã«å˜ä½ã‚’è¡¨ã™æ–‡å—åˆ—ã‚’,
  ! ã¾ãŸã¯ *unit_symbol* ã«å˜ä½ã‚’è¡¨ã™ã‚·ãƒ³ãƒœãƒ«ã‚’ä¸Žãˆã¦ãã ã•ã„.
  !
  ! unit ã«æŒ‡å®šã§ãã‚‹ã®ã¯ä»¥ä¸‹ã®æ–‡å—åˆ—ã§ã™. (å¤§æ–‡å—å°æ–‡å—ã¯åŒºåˆ¥ã—ã¾ã›ã‚“).
  !
  ! å¹´         :: dc_date_types#UNIT_YEAR
  ! æœˆ         :: dc_date_types#UNIT_MONTH
  ! æ—¥         :: dc_date_types#UNIT_DAY
  ! æ™‚         :: dc_date_types#UNIT_HOUR
  ! åˆ†         :: dc_date_types#UNIT_MIN
  ! ç§’         :: dc_date_types#UNIT_SEC
  ! ç„¡æ¬¡å…ƒæ™‚é–“ :: dc_date_types#UNIT_NONDIM
  !
  ! ã“ã‚Œã‚‰ã«è©²å½“ã—ãªã„æ–‡å—åˆ—ã‚’ *unit* ã«ä¸ŽãˆãŸå ´åˆ, ã‚¨ãƒ©ãƒ¼ã‚’ç™ºç”Ÿã•ã›ã¾ã™.
  !
  ! unit_symbol ã«æŒ‡å®šã§ãã‚‹ã®ã¯ä»¥ä¸‹ã®ã‚·ãƒ³ãƒœãƒ«ã§ã™.
  !
  ! å¹´         :: dc_date_types#UNIT_SYMBOL_YEAR
  ! æœˆ         :: dc_date_types#UNIT_SYMBOL_MONTH
  ! æ—¥         :: dc_date_types#UNIT_SYMBOL_DAY
  ! æ™‚         :: dc_date_types#UNIT_SYMBOL_HOUR
  ! åˆ†         :: dc_date_types#UNIT_SYMBOL_MIN
  ! ç§’         :: dc_date_types#UNIT_SYMBOL_SEC
  ! ç„¡æ¬¡å…ƒæ™‚é–“ :: dc_date_types#UNIT_SYMBOL_NONDIM
  !
  ! ã“ã‚Œã‚‰ã«è©²å½“ã—ãªã„ã‚·ãƒ³ãƒœãƒ«ã‚’ *unit_symbol* ã«ä¸ŽãˆãŸå ´åˆ,
  ! ã‚¨ãƒ©ãƒ¼ã‚’ç™ºç”Ÿã•ã›ã¾ã™.
  !
  ! å¼•æ•° *err* ã‚’ä¸Žãˆã¦ã„ã‚‹å ´åˆã«ã¯ *err* ã« .true. ãŒè¿”ã‚Š,
  ! ãƒ—ãƒã‚°ãƒ©ãƒ ã¯ç¶šè¡Œã—ã¾ã™.
  !
  use dc_types, only: DP, STRING
  use dc_trace, only: BeginSub, EndSub
  use dc_error, only: StoreError, DC_EBADUNIT, DC_NOERR
  use dc_string, only: StriEq
  use dc_date_generic, only: DCDiffTimeCreate, ParseTimeUnits
  use dc_date_types, only: DC_DIFFTIME, &
    & UNIT_SYMBOL_YEAR, UNIT_SYMBOL_MONTH, UNIT_SYMBOL_DAY, &
    & UNIT_SYMBOL_HOUR, UNIT_SYMBOL_MIN, UNIT_SYMBOL_SEC, UNIT_SYMBOL_NONDIM, &
    & UNIT_SYMBOL_ERR, &
    & MIN_SECONDS, HOUR_SECONDS, day_seconds, CYCLIC_MDAYS, YEAR_MONTHS
  use dc_scaledsec, only: DC_SCALED_SEC, &
    & assignment(=), DCScaledSecPutLine, &
    & operator(==), operator(>), operator(<), operator(>=), operator(<=), &
    & operator(+), operator(-), operator(*), operator(/), mod, modulo, &
    & abs, int, sign, floor
  implicit none
  type(DC_DIFFTIME), intent(out) :: diff
  real(DP), intent(in) :: value
  character(*), intent(in) :: unit
  integer, intent(in), optional :: unit_symbol
  logical, intent(out), optional :: err

  real(DP):: essec
  integer :: esmon, esday
  integer :: stat, val_int
  type(DC_SCALED_SEC):: val_scl, val_dec
  character(STRING) :: cause_c
  integer:: symbol

  character(*), parameter :: subname = 'DCDiffTimeCreate2'
continue
  call BeginSub(subname, 'value=%f', d=(/value/))
  stat = DC_NOERR
  cause_c = ''
  symbol = UNIT_SYMBOL_ERR
  if ( present(unit_symbol) ) then
    symbol = unit_symbol
  else
    symbol = ParseTimeUnits(unit)
  end if

  if ( symbol == UNIT_SYMBOL_SEC ) then
    call DCDiffTimeCreate(diff, sec=value)
    goto 999
  elseif ( symbol == UNIT_SYMBOL_NONDIM ) then
    call DCDiffTimeCreate(diff, nondim=value)
    goto 999
  end if

  val_int = int(value)
  val_scl = int(value)
  val_dec = value - int(value)

  if ( symbol == UNIT_SYMBOL_MIN ) then
    call DCDiffTimeCreate(diff, min = val_int, sclsec = val_dec * MIN_SECONDS)
  elseif ( symbol == UNIT_SYMBOL_HOUR ) then
    call DCDiffTimeCreate(diff, hour = val_int, sclsec = val_dec * HOUR_SECONDS)
  elseif ( symbol == UNIT_SYMBOL_DAY ) then
    call DCDiffTimeCreate(diff, sclday = val_scl, sclsec = val_dec * day_seconds)
  elseif ( symbol == UNIT_SYMBOL_MONTH ) then
    call DCDiffTimeCreate(diff, sclmon = val_scl, &
      & sclsec = int(val_dec * CYCLIC_MDAYS) * day_seconds)
  elseif ( symbol == UNIT_SYMBOL_YEAR ) then
    call DCDiffTimeCreate(diff, sclyear = val_scl, &
      & sclsec = int(val_dec * CYCLIC_MDAYS * YEAR_MONTHS) * day_seconds)
  else
    stat = DC_EBADUNIT
    cause_c = unit
  end if

999 continue
  call StoreError(stat, subname, err, cause_c)
  esmon = diff % mon ; esday = diff % day ; essec = diff % sec
  call EndSub(subname, 'diff (mon=%d, day=%d, sec=%f)', &
    & i=(/esmon, esday/), d=(/essec/))
end subroutine DCDiffTimeCreate2D

subroutine DCDiffTimeCreate2R(diff, value, unit, unit_symbol, err)
  use dc_types, only: DP
  use dc_date_generic, only: DCDiffTimeCreate
  use dc_date_types, only: DC_DIFFTIME
  implicit none
  type(DC_DIFFTIME), intent(out) :: diff
  real, intent(in) :: value
  character(*), intent(in) :: unit
  integer, intent(in), optional :: unit_symbol
  logical, intent(out), optional :: err
continue
  call DCDiffTimeCreate(diff, real( value, DP ), unit, unit_symbol, err)
end subroutine DCDiffTimeCreate2R

subroutine DCDiffTimeCreate2I(diff, value, unit, unit_symbol, err)
  use dc_types, only: DP
  use dc_date_generic, only: DCDiffTimeCreate
  use dc_date_types, only: DC_DIFFTIME
  implicit none
  type(DC_DIFFTIME), intent(out) :: diff
  integer, intent(in) :: value
  character(*), intent(in) :: unit
  integer, intent(in), optional :: unit_symbol
  logical, intent(out), optional :: err
continue
  call DCDiffTimeCreate(diff, real( value, DP ), unit, unit_symbol, err)
end subroutine DCDiffTimeCreate2I

subroutine DCDateTimeCreateI(time, sec)
  !
  ! dc_date_types#DC_DATETIME åž‹å¤‰æ•°ã®ç”Ÿæˆã‚’è¡Œã„ã¾ã™.
  ! å¼•æ•° sec ã«ã¯ç§’æ•°ã‚’ä¸Žãˆã¦ãã ã•ã„. å¹´æœˆæ—¥, æ™‚åˆ†ã‚’ä½¿ã£ã¦
  ! æŒ‡å®šã‚’è¡Œã„ãŸã„å ´åˆã¯ Create ã‚’åˆ©ç”¨ã—ã¦ãã ã•ã„.
  !
  use dc_types, only: DP
  use dc_date_types, only: DC_DATETIME
  use dc_date_generic, only: DCDateTimeCreate
  use dc_scaledsec, only: DC_SCALED_SEC, assignment(=)
  implicit none
  type(DC_DATETIME), intent(out):: time
  integer, intent(in):: sec
continue
  call DCDateTimeCreate(time, sec = real(sec, DP) )
end subroutine DCDateTimeCreateI

subroutine DCDateTimeCreateR(time, sec)
  !
  ! dc_date_types#DC_DATETIME åž‹å¤‰æ•°ã®ç”Ÿæˆã‚’è¡Œã„ã¾ã™.
  ! å¼•æ•° sec ã«ã¯ç§’æ•°ã‚’ä¸Žãˆã¦ãã ã•ã„. å¹´æœˆæ—¥, æ™‚åˆ†ã‚’ä½¿ã£ã¦
  ! æŒ‡å®šã‚’è¡Œã„ãŸã„å ´åˆã¯ Create ã‚’åˆ©ç”¨ã—ã¦ãã ã•ã„.
  !
  use dc_types, only: DP
  use dc_date_types, only: DC_DATETIME
  use dc_date_generic, only: DCDateTimeCreate
  use dc_scaledsec, only: DC_SCALED_SEC, assignment(=)
  implicit none
  type(DC_DATETIME), intent(out):: time
  real, intent(in):: sec
continue
  call DCDateTimeCreate(time, sec = real(sec, DP) )
end subroutine DCDateTimeCreateR

subroutine DCDateTimeCreateD(time, sec)
  use dc_types, only: DP
  use dc_date_types, only: DC_DATETIME
  use dc_date_generic, only: DCDateTimeCreate
  use dc_scaledsec, only: DC_SCALED_SEC, assignment(=)
  implicit none
  type(DC_DATETIME), intent(out):: time
  real(DP), intent(in):: sec
continue
  call DCDateTimeCreate(time, sec = sec)
end subroutine DCDateTimeCreateD

subroutine DCDiffTimeCreateI(diff, sec)
  !
  ! dc_date_types#DC_DIFFTIME åž‹å¤‰æ•°ã®ç”Ÿæˆã‚’è¡Œã„ã¾ã™.
  ! å¼•æ•° sec ã«ã¯ç§’æ•°ã‚’ä¸Žãˆã¦ãã ã•ã„. å¹´æœˆæ—¥, æ™‚åˆ†ã‚’ä½¿ã£ã¦
  ! æŒ‡å®šã‚’è¡Œã„ãŸã„å ´åˆã¯ Create ã‚’åˆ©ç”¨ã—ã¦ãã ã•ã„.
  !
  use dc_types, only: DP
  use dc_date_types, only: DC_DIFFTIME
  use dc_date_generic, only: DCDiffTimeCreate
  use dc_scaledsec, only: DC_SCALED_SEC, assignment(=)
  implicit none
  type(DC_DIFFTIME), intent(out):: diff
  integer, intent(in):: sec
continue
  call DCDiffTimeCreate(diff, sec = real(sec, DP) )
end subroutine DCDiffTimeCreateI

subroutine DCDiffTimeCreateR(diff, sec)
  !
  ! dc_date_types#DC_DIFFTIME åž‹å¤‰æ•°ã®ç”Ÿæˆã‚’è¡Œã„ã¾ã™.
  ! å¼•æ•° sec ã«ã¯ç§’æ•°ã‚’ä¸Žãˆã¦ãã ã•ã„. å¹´æœˆæ—¥, æ™‚åˆ†ã‚’ä½¿ã£ã¦
  ! æŒ‡å®šã‚’è¡Œã„ãŸã„å ´åˆã¯ Create ã‚’åˆ©ç”¨ã—ã¦ãã ã•ã„.
  !
  use dc_types, only: DP
  use dc_date_types, only: DC_DIFFTIME
  use dc_date_generic, only: DCDiffTimeCreate
  use dc_scaledsec, only: DC_SCALED_SEC, assignment(=)
  implicit none
  type(DC_DIFFTIME), intent(out):: diff
  real, intent(in):: sec
continue
  call DCDiffTimeCreate(diff, sec = real(sec, DP) )
end subroutine DCDiffTimeCreateR

subroutine DCDiffTimeCreateD(diff, sec)
  use dc_types, only: DP
  use dc_date_types, only: DC_DIFFTIME
  use dc_date_generic, only: DCDiffTimeCreate
  use dc_scaledsec, only: DC_SCALED_SEC, assignment(=)
  implicit none
  type(DC_DIFFTIME), intent(out):: diff
  real(DP), intent(in):: sec
continue
  call DCDiffTimeCreate(diff, sec = sec)
end subroutine DCDiffTimeCreateD

!-----------------------------------------------
! å¾Œæ–¹äº’æ›ç”¨
! For backward compatibility
subroutine DCDateTimeCreate1_bc(time, &
  & year, mon, day, hour, min, sec, &
  & zone, caltype, day_seconds, err)
  use dc_types, only: DP
  use dc_date_types, only: DC_DATETIME
  use dc_date_generic, only: DCDateTimeCreate
  type(DC_DATETIME), intent(out):: time
  integer, intent(in), optional:: year, mon, day, hour, min
  real(DP),intent(in), optional:: sec, day_seconds
  character(*), intent(in), optional :: zone
  integer, intent(in), optional:: caltype
  logical, intent(out), optional:: err
continue
  call DCDateTimeCreate( time, &
    & year, mon, day, hour, min, sec, &
    & zone, caltype, day_seconds = day_seconds, err = err )
end subroutine DCDateTimeCreate1_bc

subroutine DCDiffTimeCreate1_bc(diff, &
  & year, mon, day, hour, min, sec, day_seconds)
  use dc_types, only: DP
  use dc_date_types, only: DC_DIFFTIME
  use dc_date_generic, only: DCDiffTimeCreate
  type(DC_DIFFTIME), intent(out) :: diff
  integer, intent(in), optional:: year, mon, day, hour, min
  real(DP),intent(in), optional:: sec, day_seconds
continue
  call DCDiffTimeCreate( diff, &
    & year, mon, day, hour, min, sec, day_seconds )
end subroutine DCDiffTimeCreate1_bc

subroutine DCDiffTimeCreate2_bc(diff, value, unit, err)
  use dc_types, only: DP
  use dc_date_types, only: DC_DIFFTIME
  use dc_date_generic, only: DCDiffTimeCreate
  type(DC_DIFFTIME), intent(out) :: diff
  real(DP), intent(in) :: value
  character(*), intent(in) :: unit
  logical, intent(out), optional :: err
continue
  call DCDiffTimeCreate( diff, value, unit, err = err )
end subroutine DCDiffTimeCreate2_bc